How do I stop a stopwatch at a certain amount of time? - c#

I am making a words per minute program (for class) and from what I've been researching, this should work. Basically, if the timer hits 10 seconds, I want the stopwatch to stop (though this is not necessary) and stop the user from typing anymore. How would I achieve this?
public void Timer30()
{
double userCharcount = 0;
string userType;
int timeInSeconds = 10;
//new instance of stopwatch
Stopwatch stopWatch = new Stopwatch( );
//call level 1 words from wordbank
Console.WriteLine(WordBank.LevelOneWords);
stopWatch.Start( );
//**this doesn't seem to work**
if ( stopWatch.Elapsed.Seconds >= timeInSeconds )
{ Console.WriteLine("Time's up! Nice work.");
stopWatch.Stop( );
Console.ReadKey();
}
userType = Console.ReadLine( );
stopWatch.Stop( );
//capture number of characters user types to calculate WPM
userCharcount = userType.Length;
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;
// Format and display the TimeSpan value.
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}" ,
ts.Hours , ts.Minutes , ts.Seconds ,
ts.Milliseconds / 10);
Console.WriteLine("\nNice job! You finished in " + elapsedTime + "!");
Thread.Sleep(2000);
//CalculateWPMEasy(userCharCount);
}

You can't use Console.ReadLine() in that case, as that doesn't return control to your program until the user has hit Enter. Try using Console.ReadKey() in a loop, where you check that the timeout hasn't expired.

Ok, let's go through what your code does:
Console.WriteLine(WordBank.LevelOneWords);. Ok, you print some words on the console. This statement finishes normally and execution advances to the next statement.
stopWatch.Start( );. Ok, you start the stopwatch. Time starts ticking. Execution advances to the next statement.
if ( stopWatch.Elapsed.Seconds >= timeInSeconds ). Ok, this executes right after you started the stopwatch... a few nanoseconds after, maybe? If timeInSeconds is anything higher than 0, stopWatch.Elapsed.Seconds >= timeInSeconds will be false.
Execution goes on...
How and when did you expect that seconds would go by between steps 2 and 3?
So, how do you fix this? Well the easy way, is to let the user type the words, no matter how slow he might be: userType = Console.ReadLine( );. Only then check the elapsed time and if its greater than timeInSeconds inform the user he was too slow.

Related

Calculating time with hours and minutes only

I am attempting to create a timesheet calculator which takes calculates the time an employee works and I am close, with one problem.
As I perform the calculation, I only want hours and minutes to display. I am able to get that done, but that causes an issue. If the employee punches out before a full minute is elapsed, that minute is not included in the calculation.
For example, if an emp punches in at 12:00:30 and punches out at 5:00:29, that last minute is not counted in the calculation, so the time shows as 4:59 instead of 5:00.
How do I get the calculation to be based on the hours and minutes and exclude seconds completely?
This is the code I have:
private void btnPunchOut_Click(object sender, EventArgs e)
{
DateTime stopTime = DateTime.Now;
lblPunchOutTime.Text = stopTime.ToShortTimeString();
TimeSpan timeWorked = new TimeSpan();
timeWorked = stopTime - startTime;
lblTimeWorked.Text = timeWorked.ToString(#"hh\:mm");
}
Use TimeSpan.TotalSeconds perhaps...And then add 30 seconds or more, before you convert it to hours by dividing by 3600.
As in
lblTimeWorked.Text = ((timeWorked.TotalSeconds+30)/3600).ToString("0.00") + " hours";
Use Timespan.TotalHours if you want the hours.
But if you want to be accurate, you should create a separate class dedicated to calculating the hours worked by a staff member. Then you can encapsulate lots of business rules in the dedicated class. Staff have entitlements and overtime, expenses or penalty rates - so this can get complex if done properly.
If you want a calculation that really ignores the seconds, the clearest way to accomplish that is to get rid of the seconds on both the start time and the end time. It might not seem accurate because it allows a difference of one second to become a difference of one minute. But that could still be a valid business rule, that you want to subtract according the the minutes that appeared on the clock rather than the actual elapsed seconds.
In other words,
1:00:01 is adjusted to 1:00:00.
1:00:59 is adjusted to 1:00:00.
1:01:00 is "adjusted" to 1:01:00.
1:01:01 is adjusted to 1:01:00.
You can accomplish that with an extension like this:
public static class TimespanExtensions
{
public static TimeSpan TrimToMinutes(this TimeSpan input)
{
return TimeSpan.FromMinutes(Math.Truncate(input.TotalMinutes));
}
}
(I'm sure there's a more efficient way of truncating the seconds, but at least this is clear.)
Now instead of having to figure out how to calculate the difference while rounding seconds or adding seconds, you just trim the seconds before calculating the difference. Here's a unit test:
[TestMethod]
public void NumberOfMinutesIgnoresSeconds()
{
var startTime = TimeSpan.FromSeconds(59).TrimToMinutes();
var endTime = TimeSpan.FromSeconds(60).TrimToMinutes();
Assert.AreEqual(1, (endTime - startTime).TotalMinutes);
}
One Timespan represents 59 seconds, and the next one is 60, or the first second of the next minute. But if you trim the seconds and then calculate the difference you get exactly one minute.
In the context of your code,
DateTime stopTime = DateTime.Now;
lblPunchOutTime.Text = stopTime.ToShortTimeString();
var timeWorked = stopTime.TrimToMinutes() - startTime.TrimToMinutes();
lblTimeWorked.Text = timeWorked.ToString(#"hh\:mm");

A way to get the number of milliseconds in real time passed since the last call of a method

I'm calling an update function to draw a real time simulation and was wondering if there was an effective way to get the number of milliseconds passed since the last update? At the moment I have a DispatchTimer calling at regular intervals to update the simulation but the timing isn't accurate enough and ends up being about 60% slower than it should be (it varies).
I would use Stopwatch.GetTimestamp() to get a tick count, then compare the value before and after. You can convert this to timings by:
var startTicks = Stopwatch.GetTimestamp();
// Do stuff
var ticks = Stopwatch.GetTimestamp() - startTicks;
double seconds = ticks / Stopwatch.Frequency;
double milliseconds = (ticks / Stopwatch.Frequency) * 1000;
double nanoseconds = (ticks / Stopwatch.Frequency) * 1000000000;
You could also use var sw = Stopwatch.StartNew(); and sw.Elapsed.TotalMilliseconds afterwards if you just want to time different chunks of code.
Keep a variable that will not reset between calls.
Yours may not need to be static like mine.
private static DateTime _LastLogTime = DateTime.Now;
Then within the method:
// This ensures only the exact one Tick is used for subsequent calculations
// Instead of calling DateTime.Now again and getting different values
DateTime NewTime = DateTime.Now;
TimeSpan ElapsedTime = NewTime - _LastLogTime;
_LastLogTime = NewTime;
string LogMessage = string.Format("{0,7:###.000}", ElapsedTime.TotalSeconds);
I only needed down to the thousandth of a second within my string, but you can get much more accurate with the resulting TimeSpan.
Also there is a .TotalMilliseconds or even .Ticks(the most accurate) value available within the resulting TimeSpan.

intersection of two sets of data

I've been cracking my head over this algorithm for the past week and a half and i cant get it to work.
Basically i have an schedule (i know the Time value of the "borders")
and i have the red section (peoples movements in and out of the workplace). What i want is to know the time people spend at the workplace WITHIN their schedule, i dont care if they are there before or after work, or in the lunch break.
do you have any suggestions? on a mathematical theory or rule that i can apply here? or a similar problem you have seen you can point me to? i've been having a really hard time finding a solution. Any help would be appreciated.
For example:
Schedule:
7:30am (start) 12:00pm(lunchbreak)
1:30pm(endLunchBreak) 5:00pm(endOfWorkday)
People movements trough the day:
IN: 6:50am, OUT: 6:55am
IN: 7:00am, OUT: 11:45am
IN: 1:45pm, OUT: 5:05pm
So, my expected output would be a timespan of: 7:30 (it ignores time IN workplace outside of work schedule)
I would treat this as a state machine problem. There are four states: S+W+, S-W+, S+W-, S-W-.
Scheduled time corresponds to S+ states, worker present to W+ states. The objective is to add time in S+W+ to the intersection time.
The valid transitions are:
S+W+ End of schedule -> S-W+
S+W+ Worker leaves -> S+W-
S-W+ Start of schedule -> S+W+
S-W+ Worker leaves -> S-W-
S+W- End of schedule -> S-W-
S+W- Worker arrives -> S+W+
S-W- Start of schedule -> S+W-
S-W+ Worker arrives -> S-W+
Process events in time order, starting in state S-W-. If two events happen at the same time, process in either order.
On transition into S+W+, note the time. On transition out of S+W+, subtract the last noted time from the time of the transition, and add the result to the intersection time.
Break the day into 1440 one minute increments. This is your set space.
Set "S", the scheduled minutes, is a subset of that space.
Set "W", the amount of time spent on the job, is a subset of that space.
The intersection of "S" and "W" is the amount of time the person was there within their schedule (in minutes - convert to hh:mm per your needs).
Using other set algorithms you can find when they should have been there but weren't, etc.
You might want to look into using this library, but be careful, it completely ignores DateTime.Kind, is not time zone aware, and doesn't respect daylight saving time.
It is safe to use on Utc kinds.
Never use it on Local kinds.
If you use it on Unspecified kinds, make sure you understand what the context is. If it could possibly be a local time in some time zone that has DST, then your results may or may not be correct.
Other than that, you should be able to use its intersection function.
It sounds like LINQ should work well here. I've whipped up a short example, using my Noda Time library as it has better support for "time of day" than .NET, but you could adapt it if necessary.
The idea is basically that you have two collections of periods, and you're only interested in the intersection - you can find the intersection of any schedule period against any movement period - it's easy to discount periods that don't intersect by just using a 0-length period.
Here's the complete code, which does indeed give a total time of 7 hours and 30 minutes:
using System;
using System.Collections.Generic;
using System.Linq;
using NodaTime;
class Test
{
static void Main()
{
var schedule = new List<TimePeriod>
{
new TimePeriod(new LocalTime(7, 30), new LocalTime(12, 0)),
new TimePeriod(new LocalTime(13, 30), new LocalTime(17, 0)),
};
var movements = new List<TimePeriod>
{
new TimePeriod(new LocalTime(6, 50), new LocalTime(6, 55)),
new TimePeriod(new LocalTime(7, 0), new LocalTime(11, 45)),
new TimePeriod(new LocalTime(13, 45), new LocalTime(17, 05))
};
var durations = from s in schedule
from m in movements
select s.Intersect(m).Duration;
var total = durations.Aggregate((current, next) => current + next);
Console.WriteLine(total);
}
}
class TimePeriod
{
private readonly LocalTime start;
private readonly LocalTime end;
public TimePeriod(LocalTime start, LocalTime end)
{
if (start > end)
{
throw new ArgumentOutOfRangeException("end");
}
this.start = start;
this.end = end;
}
public LocalTime Start { get { return start; } }
public LocalTime End { get { return end; } }
public Duration Duration { get { return Period.Between(start, end)
.ToDuration(); } }
public TimePeriod Intersect(TimePeriod other)
{
// Take the max of the start-times and the min of the end-times
LocalTime newStart = start > other.start ? start : other.start;
LocalTime newEnd = end < other.end ? end : other.end;
// When the two don't actually intersect, just return an empty period.
// Otherwise, return the appropriate one.
if (newEnd < newStart)
{
newEnd = newStart;
}
return new TimePeriod(newStart, newEnd);
}
}

how to measure time between 2 button press ? (winCE + C#)

i need to measure time between 2 button press
in Windows-CE C#
how do do it ?
thank's in advance
DateTime.Now may not be precise enough for your needs. Link (Short short version: DateTime is extremely precise, DateTime.Now -> not so much.)
If you want better precision, use the Stopwatch class (System.Diagnostics.Stopwatch).
Stopwatch watch = new Stopwatch();
watch.Start();
// ...
watch.Stop();
long ticks = watch.ElapsedTicks;
Define a variable when the button is clicked once to NOW().
When you click a second time, measure the difference between NOW and your variable.
By doing NOW - a DateTime variable, you get a TimeSpan variable.
DateTime? time;
buttonClick(....)
{
if (time.HasValue)
{
TimeSpan diff = DateTime.Now.Subtract(time.Value);
DoSomethingWithDiff(diff);
time = null;
}
else
{
time = DateTime.Now;
}
}
See the static System.Environment.TickCount property.
This number of milliseconds elapsed since the system started, so calling it twice and subtracting the earlier value from the later will give you the elapsed time in milliseconds.

Calculate Time Remaining

What's a good algorithm for determining the remaining time for something to complete? I know how many total lines there are, and how many have completed already, how should I estimate the time remaining?
Why not?
(linesProcessed / TimeTaken) (timetaken / linesProcessed) * LinesLeft = TimeLeft
TimeLeft will then be expressed in whatever unit of time timeTaken is.
Edit:
Thanks for the comment you're right this should be:
(TimeTaken / linesProcessed) * linesLeft = timeLeft
so we have
(10 / 100) * 200 = 20 Seconds now 10 seconds go past
(20 / 100) * 200 = 40 Seconds left now 10 more seconds and we process 100 more lines
(30 / 200) * 100 = 15 Seconds and now we all see why the copy file dialog jumps from 3 hours to 30 minutes :-)
I'm surprised no one has answered this question with code!
The simple way to calculate time, as answered by #JoshBerke, can be coded as follows:
DateTime startTime = DateTime.Now;
for (int index = 0, count = lines.Count; index < count; index++) {
// Do the processing
...
// Calculate the time remaining:
TimeSpan timeRemaining = TimeSpan.FromTicks(DateTime.Now.Subtract(startTime).Ticks * (count - (index+1)) / (index+1));
// Display the progress to the user
...
}
This simple example works great for simple progress calculation.
However, for a more complicated task, there are many ways this calculation could be improved!
For example, when you're downloading a large file, the download speed could easily fluctuate. To calculate the most accurate "ETA", a good algorithm would be to only consider the past 10 seconds of progress. Check out ETACalculator.cs for an implementation of this algorithm!
ETACalculator.cs is from Progression -- an open source library that I wrote. It defines a very easy-to-use structure for all kinds of "progress calculation". It makes it easy to have nested steps that report different types of progress. If you're concerned about Perceived Performance (as #JoshBerke suggested), it will help you immensely.
Make sure to manage perceived performance.
Although all the progress bars took exactly the same amount of time in the test, two characteristics made users think the process was faster, even if it wasn't:
progress bars that moved smoothly towards completion
progress bars that sped up towards the end
Not to revive a dead question but I kept coming back to reference this page.
You could create an extension method on the Stopwatch class to get functionality that would get an estimated remaining time span.
static class StopWatchUtils
{
/// <summary>
/// Gets estimated time on compleation.
/// </summary>
/// <param name="sw"></param>
/// <param name="counter"></param>
/// <param name="counterGoal"></param>
/// <returns></returns>
public static TimeSpan GetEta(this Stopwatch sw, int counter, int counterGoal)
{
/* this is based off of:
* (TimeTaken / linesProcessed) * linesLeft=timeLeft
* so we have
* (10/100) * 200 = 20 Seconds now 10 seconds go past
* (20/100) * 200 = 40 Seconds left now 10 more seconds and we process 100 more lines
* (30/200) * 100 = 15 Seconds and now we all see why the copy file dialog jumps from 3 hours to 30 minutes :-)
*
* pulled from http://stackoverflow.com/questions/473355/calculate-time-remaining/473369#473369
*/
if (counter == 0) return TimeSpan.Zero;
float elapsedMin = ((float)sw.ElapsedMilliseconds / 1000) / 60;
float minLeft = (elapsedMin / counter) * (counterGoal - counter); //see comment a
TimeSpan ret = TimeSpan.FromMinutes(minLeft);
return ret;
}
}
Example:
int y = 500;
Stopwatch sw = new Stopwatch();
sw.Start();
for(int x = 0 ; x < y ; x++ )
{
//do something
Console.WriteLine("{0} time remaining",sw.GetEta(x,y).ToString());
}
Hopefully it will be of some use to somebody.
EDIT:
It should be noted this is most accurate when each loop takes the same amount of time.
Edit 2:
Instead of subclassing I created an extension method.
Generally, you know three things at any point in time while processing:
How many units/chunks/items have been processed up to that point in time (A).
How long it has taken to process those items (B).
The number of remaining items (C).
Given those items, the estimate (unless the time to process an item is constant) of the remaining time will be
B * C / A
I made this and it works quite good, feel free to change the method signature according to your variable types or also to the return type, probably you would like to get the TimeSpan object or just the seconds...
/// <summary>
/// Calculates the eta.
/// </summary>
/// <param name="processStarted">When the process started</param>
/// <param name="totalElements">How many items are being processed</param>
/// <param name="processedElements">How many items are done</param>
/// <returns>A string representing the time left</returns>
private string CalculateEta(DateTime processStarted, int totalElements, int processedElements)
{
int itemsPerSecond = processedElements / (int)(processStarted - DateTime.Now).TotalSeconds;
int secondsRemaining = (totalElements - processedElements) / itemsPerSecond;
return new TimeSpan(0, 0, secondsRemaining).ToString();
}
You will require to initialize a DateTime variable when the processing starts and send it to the method on each iteration.
Do not forget that probably your window will be locked if the process is quite long, so when you place the return value into a control, don't forget to use the .Refresh() method of it.
If you are using threads then you can attempt to set the text using the Invoke(Action) method, would be easier to use this extension method to archieve it easily.
If you use a console application, then you should not have problems displaying the output line by line.
Hope it helps someone.
It depends greatly on what the "something" is. If you can assume that the amount of time to process each line is similar, you can do a simple calculation:
TimePerLine = Elapsed / LinesProcessed
TotalTime = TimePerLine * TotalLines
TimeRemaining = TotalTime - LinesRemaining * TimePerLine
there is no standard algorithm i know of, my sugestion would be:
Create a variable to save the %
Calculate the complexity of the task you wish to track(or an estimative of it)
Put increments to the % from time to time as you would see fit given the complexity.
You probably seen programs where the load bar runs much faster in one point than in another. Well that's pretty much because this is how they do it. (though they probably just put increments at regular intervals in the main wrapper)
Where time$("ms") represents the current time in milliseconds since 00:00:00.00, and lof represents the total lines to process, and x represents the current line:
if Ln>0 then
Tn=Tn+time$("ms")-Ln 'grand total of all laps
Rn=Tn*(lof-x)/x^2 'estimated time remaining in seconds
end if
Ln=time$("ms") 'start lap time (current time)
That really depends on what is being done... lines are not enough unless each individual line takes the same amount of time.
The best way (if your lines are not similar) would probably be to look at logical sections of the code find out how long each section takes on average, then use those average timings to estimate progress.
If you know the percentage completed, and you can simply assume that the time scales linearly, something like
timeLeft = timeSoFar * (1/Percentage)
might work.
I already knew the percentage complete & time elapsed, so this helped me:
TimeElapsed * ((100 - %complete) / %complete) = TimeRemaining
I then updated this value every time %complete changed, giving me a constant varying ETA.
There is 2 ways of showing time
Time elapsed and Time Remaining overall:
so elapsed will increase but remaining will be likely stable total time needed (if per second is stable)
Time elapsed and Time Left:
so Time Left = Total Needed - Elapsed
My idea/formula is more likely like this:
Processed - updated from running thread from 0 to Total
I have timer with 1000ms interval that calculates processed per second:
processedPerSecond = Processed - lastTickProcessed;
lastTickProcessed = Processed; //store state from past call
processedPerSecond and lastTickProcessed are global variables out of timer method
Now if we would like to get how many seconds is required to complete the processing (in ideal constant assumption)
totalSecondsNeeded = TotalLines / PerSecond
but we want to show case 2. TimeLeft so
TimeLeftSeconds = (TotalLines - Processed) / PerSecond
TimeSpan remaining = new TimeSpan(0, 0, (transactions.Count - Processed) / processedPerSecond);
labelTimeRemaining.Text = remaining.ToString(#"hh\:mm\:ss");
Of course TimeLeftSeconds will "jump" if PerSecond jumps, so if past PerSecond was 10 then 30 then back to 10, the user will see it.
There is a way to calculate average, but this may not show real time left if process speeds up at the end
int perSecond = (int)Math.Ceiling((processed / (decimal)timeElapsed.TotalSeconds)); //average not in past second
So it may be the choice for a developer to "pick" a method that will be most accurate based on prediction of how "jumpy" the processing is
We could also calculate and save each PerSecond, then take last 10 second and made average, but in this case user will have to wait 10 seconds to see first calculation
or we could show time left starting from first per second and then progressively average summing up to 10 last PerSecond
I hope my "jumpy" thoughts will help someone to build something satisfying
How about this....
I used this to walk through a set of records (rows in an Excel file, in one case)
L is the current row number
X is the total number of rows
dat_Start is set to Now() when the routine begins
Debug.Print Format((L / X), "percent") & vbTab & "Time to go:" & vbTab & Format((DateDiff("n", dat_Start, Now) / L) * (X - L), "00") & ":" & Format(((DateDiff("s", dat_Start, Now) / L) * (X - L)) Mod 60, "00")
PowerShell function
function CalculateEta([datetime]$processStarted, [long]$totalElements, [long]$processedElements) {
$itemsPerSecond = $processedElements / [DateTime]::Now.Subtract($processStarted).TotalSeconds
$secondsRemaining = ($totalElements - $processedElements) / $itemsPerSecond
return [TimeSpan]::FromSeconds($secondsRemaining)
}
I prefer System.Threading.Timer rather than System.Diagnostics.Stopwatch.
System.Threading.Timer, which executes a single callback method on a
thread pool thread
The following code is an example of a calculating elapsed time with Threading.Timer.
public class ElapsedTimeCalculator : IDisposable
{
private const int ValueToInstantFire = 0;
private readonly Timer timer;
private readonly DateTime initialTime;
public ElapsedTimeCalculator(Action<TimeSpan> action)
{
timer = new Timer(new TimerCallback(_ => action(ElapsedTime)));
initialTime = DateTime.UtcNow;
}
// Use Timeout.Infinite if you don't want to set period time.
public void Fire() => timer.Change(ValueToInstantFire, Timeout.Infinite);
public void Dispose() => timer?.Dispose();
private TimeSpan ElapsedTime => DateTime.UtcNow - initialTime;
}
BTW You can use System.Reactive.Concurrency.IScheduler (scheduler.Now.UtcDateTime) instead of using DateTime directly, if you would like to mock and virtualize the datetime for unit tests.
public class PercentageViewModel : IDisposable
{
private readonly ElapsedTimeCalculator elapsedTimeCalculator;
public PercentageViewModel()
{
elapsedTimeCalculator = new ElapsedTimeCalculator(CalculateTimeRemaining))
}
// Use it where You would like to estimate time remaining.
public void UpdatePercentage(double percent)
{
Percent = percent;
elapsedTimeCalculator.Fire();
}
private void CalculateTimeRemaining(TimeSpan timeElapsed)
{
var timeRemainingInSecond = GetTimePerPercentage(timeElapsed.TotalSeconds) * GetRemainingPercentage;
//Work with calculated time...
}
public double Percent { get; set; }
public void Dispose() => elapsedTimeCalculator.Dispose();
private double GetTimePerPercentage(double elapsedTime) => elapsedTime / Percent;
private double GetRemainingPercentage => 100 - Percent;
}
In Python:
First create a array with the time taken per entry, then calculate the remaining elements and calculate average time taken
import datetime from datetime
import time
# create average function**
def average(total):
return float(sum(total)) / max(len(total), 1)
# create array
time_elapsed = []
# capture starting time
start_time = datetime.now()
# do stuff
# capture ending time
end_time = datetime.now()
# get the total seconds from the captured time (important between two days)
time_in_seconds = (end_time - start_time).total_seconds()
# append the time to a array
time_elapsed.append(time_in_seconds)
# calculate the remaining elements, then multiply it with the average time taken
est_time_left = (LastElement - Processed) * average(time_elapsed)
print(f"Estimated time left: {time.strftime('%H:%M:%S', time.gmtime(est_time_left))}")
** timeit() with k=5000 random elements and number=1000
def average2(total):
avg = 0
for e in total: avg += e
return avg / max(len(total),1)
>> timeit average 0.014467999999999925
>> timeit average2 0.08711790000000003
>> timeit numpy.mean: 0.16030989999999967
>> timeit numpy.average: 0.16210096000000003
>> timeit statistics.mean: 2.8182458

Categories

Resources