Hello people of stackoverflow.I am having an issue when i try to take a time-span and convert it to a string.
Here is the code:
private void timer1_Tick(object sender, EventArgs e)
{
timeLeft = timeLeft - 1;
TimeLabel.Text = TimeSpan.FromMilliseconds(timeLeft).ToString("h'h 'm'm 's's'");
}
Note that timeLeft is in milliseconds.
However whenever i try to pass this i get 2 sets of minutes sections.
Like this:
Although it should be this amount of time :
I see you´re updating the label every timer ticks and although it´s not shown in the code it looks like your timer interval its set to 1 second probably, Am I right?.
The first thing you´re doing bad is trusting the 1 second interval you set up previously in your timer and hard-coding your code to that interval. The fact is you can´t rely in the timer interval to be precise because most of the timers have a awful resolution time of approximately 14 - 16 ms therefore that´s not a precise way to measure time.
You should use instead the time System.Diagnostics.Stopwatch class which uses the Win32 APIs QueryPerformanceFrequency and QueryPerformanceCounter. Those are the more reliable ways and fast ways to measure time due to the fact that Windows isn´t a Real Time Operation System.
As for how the code will look using I let a sample which should be pretty easy to adapt for you. Besides I include a solution for your TimeSpan - String translation trouble.
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
Console.WriteLine("Starting..");
sw.Start();
Console.ReadLine();
sw.Stop();
Console.WriteLine("Elapsed time {0}:{1}:{2}:{3}", sw.Elapsed.Hours.ToString("00"), sw.Elapsed.Minutes.ToString("00"), sw.Elapsed.Seconds.ToString("00"), sw.Elapsed.Milliseconds);
}
}
Be careful while using the System.Diagnostics.Stopwatch properties, there is a big difference in using the Elapsed.Ticks property and the ElapsedTicks property which it´s explained here.
Hope it helps!!
Due to the fact that there won't be any guarantee that the timer will be fired exactly every millisecond, you have to save a start time and then calculate the elapsed time by subtracting the start time from the current time.
Here is a code snippet to illustrate it:
private DateTime _StartTime;
private void OnCheckBoxTimerEnabledCheckedChanged(object sender, EventArgs e)
{
_StartTime = DateTime.UtcNow;
timer.Enabled = checkBoxTimerEnabled.Checked;
}
private void OnTimerTick(object sender, System.EventArgs e)
{
var now = DateTime.UtcNow;
labelTimeElapsed.Text = (now - _StartTime).ToString("h'h 'm'm 's's'");
}
In that case you also don't need to fire the timer every millisecond. Just fire it every 100ms to be accurate enough for the users eye.
And another tip:
If you need to calculate relative times on your own you should always stick to DateTime.UtcNow and NOT DateTime.Now. So you won't get into trouble when your timer is running when you switch from normal time to summer time or vice versa.
there is nothing wrong with your code. but i guess you Think there is since the above sample shows
2:02:56 and the other 02:03:00 wich is rather Close missing some 3200 milliseconds...
what is the actual value of timeLeft?
Read some more in the documentation on customizing timespan strings
Using a Timer's Tick event to track passing time will result in inaccuracies as Lasse V. Karlsen mentioned in their comment on your question.
What you want to do is store a timestamp (DateTime.Now) when the timer begins, and compare that with a new DateTime.Now each time the timer ticks, like so:
DateTime timestamp;
TimeSpan timeLeft;
private void begin_timer()
{
timestamp = DateTime.Now;
timer1.start();
}
private void timer1_Tick(object sender, EventArgs e)
{
timeLeft = DateTime.Now - timestamp;
TimeLabel.Text = timeLeft.ToString("HH:mm:ss.fff");
}
Related
I'm just trying to make a basic mm:ss timer for a little sports scoreboard.
I currently have
int i = 0;
private void matchTimer_Tick(object sender, EventArgs e)
{
i++;
timeDisplay.Text = i.ToString("00:00");
}
But this fails because it doesn't account for minutes, so once time gets to 60, it just carries on
00:60
00:61
00:62
...
But I want it to be
01:00
01:01
01:02
...
and then stop at 80 minutes
You have more problems than you think. You're currently relying on the timer ticking exactly once per second. Don't do that - instead, use a System.Diagnostics.Stopwatch to measure the elapsed time, and then update the display by formatting the value of Stopwatch.Elapsed:
timeDisplay.Text = stopwatch.Elapsed.ToString("mm':'ss");
(See the Custom TimeSpan format strings documentation for more details.)
Timespan is made for that.
timeDisplay.Text = new TimeSpan(0, 0, i).ToString("mm\\:ss")
Your format string is incorrect. You should create a TimeSpan value and format that.
I used the following line of code
int pp = DateTime.Now.Hour;
and it is ok. I wrote
label1.text=pp.tostring();
for verification and it works, but if I open my form at 19:59 (eg.) in label1 appears 19 and after one minute, when the clock is 08:00, the value in label1 is not changing and still appears 19, not 20.
After that, if I close the form and reopen it, the number in label1 is 20.
How can I modify the value from datetime.now.hour in real time, while the form is running?
thank you
Since you are using the "form" terminology, I'll assume Windows Forms, and the easiest way would be adding a Timer component, set a reasonable Interval (reasonable meaning how long is it the maximum you can afford to delay when the hour changes before the label changes... the higher the interval, the less CPU your process will occupy) on it, and on its Tick event, do your:
static void MyTimer_Tick(object sender, EventArgs e)
{
int pp = DateTime.Now.Hour;
label1.text=pp.tostring();
}
You need to implement a Timer, and have its Elapsed event update label1.text. Simply calling DateTime.Now.Hour is not enough, as that only updates it once. It does not set a recurring method to constantly update.
using System.Timers;
namespace Example {
static Timer _timer;
static void Main() {
_timer = new Timer(1000); // Update every 1 second.
_timer.Elapsed += UpdateMyLabel;
_timer.Start();
}
static void UpdateMyLabel(object sender, ElapsedEventArgs e) {
label1.Text = DateTime.Now.Hour;
}
}
I would deduce the Label class and use timer tick for updating the label. Just like in OOP ;)
I'm trying to develop simple timer which can save its last value and continue from it at the new app start.
Stopwatch class is not serializable and even cannot be initialized in order to be started from specific time. But it works great. Benchmark showed that stopwatch's 1 minute is really 1 minute.
I tried to use TimeSpan in the following way:
private TimeSpan timerNew = new TimeSpan();
private DispatcherTimer dispatcherTimer = new DispatcherTimer();
public MainWindow()
{
InitializeComponent();
dispatcherTimer.Interval = TimeSpan.FromSeconds(1);
dispatcherTimer.Tick += Timer_Tick;
}
private void Timer_Tick(object sender, EventArgs e)
{
timerNew += new TimeSpan(0, 0, 0, 1);
TbTimer.Text = String.Format("{0:00}:{1:00}:{2:00}",
timerNew.Hours, timerNew.Minutes, timerNew.Seconds);
}
private void ButtonStart_OnClick(object sender, RoutedEventArgs e)
{
dispatcherTimer.Start();
}
private void ButtonStop_OnClick(object sender, RoutedEventArgs e)
{
dispatcherTimer.Stop();
}
private void ButtonReset_OnClick(object sender, RoutedEventArgs e)
{
timerNew = new TimeSpan();
TbTimer.Text = "00:00:00";
}
When I checked it against real stopwatch, I found out that this timer implementation lost 2 seconds per minute.
I also tried my own Timer implementation which is simple class with ulong field, which is incremented on each dispatcherTimer tick. And UI shows results after transformation of seconds to hours, minutes and so on. But it also loses 2 seconds per minute comparing to real stopwatch.
Why these 2 seconds are lost? What is an alternative to Stopwatch for usage in a customizable timer?
The Windows thread scheduler is not a "real-time" scheduler, as Windows is not a "real-time OS". In other words, all timing and scheduling is done on a "best effort" basis, without any guarantee of exact precision. In addition, this always results in lost time, because the one guarantee you do have is that scheduling will not happen early. So when there's an imprecision, it's always in the direction of "late".
The Stopwatch class works because it uses CPU-supported performance counters, which doesn't rely on the OS scheduler. The hardware itself tracks the elapsed time and provides the information you need.
I recommend against the use of DateTime.UtcNow for measuring elapsed time, for two reasons: first, the clock DateTime uses is adjustable, and so even using UTC time (which at least would compensate for automatic adjustments due to Daylight Saving Time) is not guaranteed to be accurate. Second, your specific scenario seems to involve an issue where you want to serialize the current state and restore it, which DateTime.UtcNow doesn't address anyway.
Instead, you should make your own serializable stopwatch class, which uses Stopwatch itself as the basis, but which stores a base elapsed value that you add to the Stopwatch's elapsed value.
For example:
class SerializableStopwatch
{
public TimeSpan BaseElapsed { get; set; }
public TimeSpan Elapsed { get { return _stopwatch.Elapsed + BaseElapsed; } }
private Stopwatch _stopwatch = new Stopwatch();
// add whatever other members you want/need from the Stopwatch class,
// simply delegating the operation to the _stopwatch member. For example:
public void Start() { _stopwatch.Start(); }
public void Stop() { _stopwatch.Stop(); }
// etc.
}
How exactly you would serialize the above is up to you. In the simplest scenario, you can just format the Elapsed property as a string to save the value, and then when you want to restore the object, parse that value, create a new instance of the above class, and then assign the value to the BaseElapsed property.
For additional discussion on the topic, you might find Eric Lippert's blog article Precision and accuracy of DateTime useful and interesting.
I'm beginner to programming. This is my code:
private void timer1_Tick(object sender, EventArgs e)
{
sec++;
textBoxSeconds.Text = sec.ToString();
if (sec > 59)
{
sec = 0;
textBoxSeconds.Text = sec.ToString();
min++;
textBoxMinutes.Text = min.ToString();
}
}
time goes too fast;/ and it stops for few sec sometimes. Hope someone can help me:)
*EDIT//*
thanks for help:) it works, but i still have a problem i didnt menton earlier. time stops sometimes for 1-2 sec, idk why. maybe because of some loops?
This is the wrong approach. When you program starts just save a DateTime instance, i.e. startTime. In your timer tick handler calculate the difference between the current time and the start time and display that.
private DateTime startTime = DateTime.Now;
private void timer1_Tick(object sender, EventArgs e)
{
var delta = DateTime.Now - startTime;
textBoxSeconds.Text = delta.Seconds.ToString("n0");
textBoxMinutes.Text = Math.Floor(delta.TotalMinutes).ToString("n0");
}
Using your code, I can say probably you haven't set the timer Interval, so:
timer1.Interval = 1000; //1000 ms = 1 second
Then you can improve something in the Tick event:
private void timer1_Tick(object sender, EventArgs e)
{
sec++;
if (sec == 60)
{
sec = 0;
min++;
}
textBoxSeconds.Text = sec.ToString();
textBoxMinutes.Text = min.ToString();
}
So use the DateTime class, it's the best solution.
EDIT:
DateTime startTime = DateTime.Now;
void timer1_Tick(object sender, EventArgs e)
{
TimeSpan time = DateTime.Now - startTime;
textBoxSeconds.Text = string.Format("{0:0#}", time.Seconds);
textBoxMinutes.Text = string.Format("{0:0#}", time.Minutes);
}
I agree about startTime - it is mandatory. I've also commented about DataTime.UtcNow - this is correct way.
About your second problem with 1..2 seconds lag - this is because timer's ticks racing side by side with seconds ticks.
1) If your timer will be triggered in 998ms instead of 1000ms, you can read the same amount of second and this number will stay before next tick.
2) Because application is not in real-time priority from OS point of view, it can be held for several seconds (e.g. for rendering multimedia stuff by other app) and you can notice a skip of 1 second...
To solve 1st reason and facilitate 2nd try to increase ticks count by decreasing Interval to 500 or 333.
For more advanced strategy that preserves your resources, you should still use 1000ms but synchronize you timer periodically with each half second crossing using dateTime.Milliseconds. That will maximize probability of avoiding side-by-side racing problem without extra ticks.
I'm writing trading software and need to QoS one method that should not be executed more often than 10 times per second. As I'm begginer in C# and almost not familar with libraries I would like to double-check if my code is "optimal". I'm using Stopwatch because I don't know any other timers in C#.
Stopwatch updateStopwatch = Stopwatch.StartNew();
private void update()
{
if (updateStopwatch.ElapsedMilliseconds < 100)
{
Console.WriteLine("!skip update " + updateStopwatch.ElapsedMilliseconds);
return;
} else
{
Console.WriteLine("!update");
updateStopwatch.Restart();;
}
// do work here
}
upd Now it seems that Stopwatch is pretty good for this task. However probably it would be too slow, if so probably DateTime would be better. sell also Stopwatch vs. using System.DateTime.Now for timing events
Your technique of using Stopwatch is the best solution to prevent the code from executing more frequently. As others have said, using a Timer is a better solution if you want to make sure that the method is executed on a schedule.
Any approach based on DateTime is fundamentally broken because it will fail when the date changes. This is especially noticeable during the Daylight Saving Time switches. When we "spring ahead", there's the potential of the update running twice in quick succession because the code thinks that it's been an hour since the previous update. That's not too bad. But when we "fall back", the update will be suspended for a full hour because the last update time is set an hour ahead.
The same kind of thing can happen, although not as severely, if your computer is set to update its time periodically from an NTP server. If the time is set ahead, then there is the potential for two updates to happen in quick succession. If the time is set back, there's the potential for updates not to happen for the amount of time the clock was set back.
There are ways around the problem (such as using the absolute value of the number of milliseconds), but then you're just putting a bandage on a broken solution. You shouldn't depend on DateTime for intervals like this because your program isn't in control of the system clock--it can change at any time.
Stopwatch is the only reasonable solution here because it depends on the CPU's performance counter, which only increases. You don't have the problems of somebody setting the counter back, and you don't have the rollover problems you would encounter with something like Environment.TickCount.
There's some idea that Stopwatch incurs a performance penalty that DateTime doesn't. My testing shows that to be untrue.
Stopwatches and timers are fairly expensive objects to use. You could simply hold a DateTime object as a variable and perform a comparison.
DateTime lastCheck = DateTime.Now;
private void update()
{
// DateTime.Subtract returns a TimeSpan
int elapsed = DateTime.Now.Subtract(lastCheck).Milliseconds;
if (elapsed < 100)
{
Console.WriteLine("!skip update " + elapsed.ToString());
return;
} else
{
Console.WriteLine("!update");
lastCheck = DateTime.Now;
}
// do work here
}
I would not use a Stopwatch or anything other Timer-like. Instead just store the time of the method call and only execute the subsequent calls if the difference between the current and the stored time is bigger than 100ms.
You could implement a helper class to do this in a more general way:
public class TimedGate
{
private DateTime m_Last;
private TimeSpan m_Gap;
public TimedGate(TimeSpan gap)
{
m_Gap = gap;
}
public bool TryEnter()
{
DateTime now = DateTime.UtcNow;
if (now.Subtract(m_Last) > m_Gap)
{
m_LastEntered = now;
return true;
}
return false;
}
}
Use it like this:
TimedGate m_UpdateGate = new TimedGate(TimeSpan.FromMilliseconds(100));
private void Update()
{
if (m_UpdateGate.TryEnter())
{
Console.WriteLine("!update");
// do work here
}
else
{
Console.WriteLine("!skip update");
}
}
There is always the System.Timer timer.
That is probably easier to work with than the Stopwatch (which normally is used to measure how long time things take).
Code:
var timer = new System.Timers.Timer();
// Hook up the Elapsed event for the timer using a lambda
timer.Elapsed += (o, e) => Console.WriteLine("Timer elapsed");
// Set the Interval to 100 ms
timer.Interval = 100;
// Start the timer.
timer.Enabled = true;
MSDN docs: http://msdn.microsoft.com/en-us/library/system.timers.timer(v=VS.100).aspx