Reputation: 778
I'm having following code to show the current time:
static void Main(string[] args)
{
while (true)
{
ShowDate(GetTime(),GetDate());
//Here's my issue:
System.Threading.Thread.Sleep(1000);
}
}
//Clear Console and write current Date again.
static void ShowDate(String time, String date)
{
Console.Clear();
Console.WriteLine(date);
Console.WriteLine(time);
}
static string GetTime()
{
string timeNow = DateTime.Now.ToString("HH:mm:ss");
return timeNow;
}
static string GetDate()
{
string dateNow = DateTime.Now.ToString("dd.MM.yy");
return dateNow;
}
Well, in my understanding, Thread.Sleep(1000)
only shows the time every second measured after start of the program. So it doesn't show the perfectly correct time. I could try a lower value for Thread.Sleep()
, but that's still kinda inaccurate and probably becomes kind of inefficient.
Is there any possible way to, for example, update the time every time the system itself updates its time? Something like an event listener
maybe?
Upvotes: 0
Views: 1891
Reputation: 120450
I'd approach this with a custom clock class that emits events every second. By measuring the remaining time before the next second is due to elapse, we can wait until that moment, then fire an event.
Leveraging async/await
for the benefit it brings in code clarity and IDisposable
for the clean-up, this might look something like this:
void Main()
{
using(var clock = new Clock())
{
clock.Tick += dt => Console.WriteLine(dt);
Thread.Sleep(20000);
}
}
//sealed so we don't need to bother with full IDisposable pattern
public sealed class Clock:IDisposable
{
public event Action<DateTime> Tick;
private CancellationTokenSource tokenSource;
public Clock()
{
tokenSource = new CancellationTokenSource();
Loop();
}
private async void Loop()
{
while(!tokenSource.IsCancellationRequested)
{
var now = DateTime.UtcNow;
var nowMs = now.Millisecond;
var timeToNextSecInMs = 1000 - nowMs;
try
{
await Task.Delay(timeToNextSecInMs, tokenSource.Token);
}
catch(TaskCanceledException)
{
break;
}
var tick = Tick;
if(tick != null)
{
tick(DateTime.UtcNow);
}
}
}
public void Dispose()
{
tokenSource.Cancel();
}
}
Upvotes: 3
Reputation: 4371
As You have written, this would refresh (write) time every second - 0, 1, 2, 3 .. But if the program would start in some middle time, it would go like 1.3, 2.3, 3.3
This is not always expected behaviour, but an Event
for each time change, would be also consuming - You might maybe know there is existing some "system time", which is counted in the Ticks
.
Tick happens each time processor jumps
to next instruction and as it has some frequency
, it can re-calculate the current time from it.
However .NET
allows You to use some pre-build Timers
, which can be run with precission of milisecond.
Example code as in here:
using System;
using System.Threading;
public static class Program
{
public static void Main()
{
// Create a Timer object that knows to call our TimerCallback
// method once every 2000 milliseconds.
Timer t = new Timer(TimerCallback, null, 0, 2000);
// Wait for the user to hit <Enter>
Console.ReadLine();
}
private static void TimerCallback(Object o)
{
// Display the date/time when this method got called.
Console.WriteLine("In TimerCallback: " + DateTime.Now);
// Force a garbage collection to occur for this demo.
GC.Collect();
}
}
Important: You are using Thread.Sleep()
, which will cause Thread
to stopp all its work, this is really unsufficient way of delaying some activity and should be used minimally. There are some special ocasions, where it is really useable, but this is surely not the one.
Upvotes: 1
Reputation: 4883
Instead of using a Thread.Sleep to stop the Thread execution, I think you´ll be better using a conventional Timer:
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer(1000);
timer.Elapsed += Tim_Elapsed;
timer.Start();
}
private void Tim_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
ShowDate();
}
Upvotes: 1