I can't get the timer to fire once a minute on the minue, 1:00, 1:01, 1:02 etc. Instead, when the timer executes drifts by a couple of seconds each iteration
internal void StartTimer()
{
DateTime nowEastern = CalendarEntity.Calendar.GetEasternTime();
int secondsInterval = 5;
double additionalSeconds = secondsInterval - nowEastern.TimeOfDay.TotalSeconds % secondsInterval;
if (additionalSeconds == 0)
{
additionalSeconds = 1;
}
var nearestOnOneMinutes = new DateTime(
nowEastern.Year,
nowEastern.Month,
nowEastern.Day,
nowEastern.Hour,
nowEastern.Minute,
nowEastern.Second
).AddSeconds(additionalSeconds);
TimeSpan timeToStart = nearestOnOneMinutes.Subtract(nowEastern);
TimeSpan tolerance = TimeSpan.FromSeconds(1);
if (timeToStart < tolerance)
{
timeToStart = TimeSpan.Zero;
}
timer_onem = new System.Threading.Timer(OnTimedEvent, null,
(int)timeToStart.TotalMilliseconds, Timeout.Infinite);
}
private static void OnTimedEvent(object o)
{
var minute = DateTime.Now.Minute;
var second = DateTime.Now.Second;
if (minute != lastMinute && second % 60 < 2)
{
lastMinute = minute;
CodeToExecute();
}
}
static void CodeToExecute()
{
double tms = 60000;
// code here
int wait = 60 - System.DateTime.Now.Second;
timer_onem.Change(Convert.ToInt64(tms) - wait, Timeout.Infinite);
}
EDIT 1
I changed the interval so that it fires once a second and then check that the minute has changed. Still drifts
timer_onem = new System.Threading.Timer(OnTimedEvent, null,
(int)timeToStart.TotalMilliseconds, 1000);
private static void OnTimedEvent(object o)
{
var minute = DateTime.Now.Minute;
if (minute != lastMinute)
{
lastMinute = minute;
CodeToExecute();
}
}
private static void CodeToExecute()
{
if (bGenerate)
{
double tms = 1000;
// code
timer_onem.Change(Convert.ToInt64(tms), 1000);
}
}
A Timer is only guaranteed to be no faster than Interval.
So you need to call it, say every second and check for the full minute.
For even better precision you would have to check every 1/2 second or better.
It is a basic rule of information theory that says that to measure with a given resolution (1 second in your case) you need to sample with better than twice that resolution. Hence to measure 20kHz you need a smpling rate better than 2x20kHz, say 44.1kHz. (Recognize the numbers?)
If you don't want to call it so often for simply getting one precise point in time, you could write a little more involved code that on each Tick resets the Timer.Interval to a little under half of the remaining time until the next full minute until it is under say 500ms..
There are rather complex things going on in your code wrt to setting up the expected time, though; do make sure they are not the real problem. There should not be a growing drift from the timer's lack of precision, unless you 'collect' the errors..
Related
I am trying to refresh my frame every 17ms with a timer.
Timer timer = new Timer(17);
timer.Elapsed += ResetFrame;
timer.Start();
But instead of waiting for 17ms and then repeating, it waited for the frame refresh to complete and then wait for 17msfor the next repeat. This causes the frame to be refreshed every 28ms. How to synchronize it with real time?
To have a real time timer having a very short interval, you can take a look at this article:
Real Time Timer in C#
In Dot Net, following timers are not real time.
System.Windows.Forms.Timer
System.Timers.Timer
System.Threading.Timer
Means if you want to run your code at every 100 millisecond then above
timer fire even around 110 millisecond or later. Windows is not a real
time OS because of this .Net is also not a real time.
To create a real time timer in C# you have to write custom code that
can hold CPU to run your code at right time.
class Program
{
static void Main(string[] args)
{
Console.ReadLine();
Console.WriteLine("Running");
RealTimeTimerTest obj = new RealTimeTimerTest();
obj.Run();
}
}
public class RealTimeTimerTest
{
List<DateTime> lst = new List<DateTime>();
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
public void Run()
{
int Tick = 100;
int Sleep = Tick - 20;
long OldElapsedMilliseconds = 0;
sw.Start();
while (sw.IsRunning)
{
long ElapsedMilliseconds = sw.ElapsedMilliseconds;
long mod = (ElapsedMilliseconds % Tick);
if (OldElapsedMilliseconds != ElapsedMilliseconds && (mod == 0 || ElapsedMilliseconds > Tick))
{
//-----------------Do here whatever you want to do--------------Start
lst.Add(DateTime.Now);
//-----------------Do here whatever you want to do--------------End
//-----------------Restart----------------Start
OldElapsedMilliseconds = ElapsedMilliseconds;
OldElapsedMilliseconds = 0;
sw.Reset();
sw.Start();
System.Threading.Thread.Sleep(Sleep);
//-----------------Restart----------------End
}
//------------Must define some condition to break the loop here-----------Start
if (lst.Count > 500)
{
Write();
break;
}
//-------------Must define some condition to break the loop here-----------End
}
}
private void Write()
{
System.IO.StreamWriter sw = new System.IO.StreamWriter("d:\\text.txt", true);
foreach (DateTime dtStart in lst)
sw.WriteLine(dtStart.ToString("HH:mm:ss.ffffff")); sw.Close();
}
}
Also that:
Most accurate timer in .NET?
High resolution timer
High resolution timer in C#
Microsecond and Millisecond C# Timer
Precision-Repeat-Action-On-Interval-Async-Method
I'm writing an app where a user specifies a length of time, length of an interval and a length of time in between intervals. I want to have a timer label showing the user the total time but then I also want to have a label showing the work status (recording if in the interval, break if between interval time and break end).
Heres an Example: Total time = 2 min, Interval = 20 seconds, Break = 10 seconds
In this example there will be 4 intervals. So from 0:00-0:19 I want to display "Recording" and then from 0:20-0:29 I want to display break and then from 0:30-0:49 I display "Recording" and 0:50-0:59 I display "Break" and so on. All while the timer counts the time.
So I thought this would be pretty straightforward but what seems to happen is the timer increments properly but after the 1st interval the label doesnt switch from break to recording until 0:31 or 0:32 so it looks a little delayed.
Here is the code I am using currently (Note obs is an object Im passing in that has data from user input).
int TotalInterval = obs.Interval + obs.Break;
int WorkingInterval = obs.Interval;
int NumberOfIntervals = (obs.Duration*60) / TotalInterval;
DateTime ObservationEnd = obs.DateCreated.AddMinutes(obs.Duration);
Timer.Text = "Starting Timer";
int minutes = 0;
int seconds = 0;
int InIntervalCounter = 0;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
// called every 1 second
Timer.Text = "Started";
if (ObservationEnd < DateTime.UtcNow)
{
Timer.Text = "Time Over";
Results.IsVisible = true;
return false;
}
else
{
seconds++;
InIntervalCounter++;
if (InIntervalCounter > WorkingInterval)
IntervalOrBreak.Text = "Break";
if (InIntervalCounter > TotalInterval)
{
IntervalOrBreak.Text = "Recording";
InIntervalCounter = 0;
}
Timer.Text = "Time: " + minutes + ":" + seconds.ToString("D2");
return true;
}
});
I'm pretty new to app development/xamarin so any help is greatly appreciated.
Try using simple Threads with Thead.sleep() like this:
final long delay_millis = 100;
Thread thread_something;
thread_something = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
long start_time = SystemClock.elapsedRealtime();
// Do some task
long time_need_for_delay = (start_time + delay_millis) - SystemClock.elapsedRealtime();
if(time_need_for_delay > 0)
thread_something.sleep(time_need_for_delay);
} catch (Exception e) { }
}
}
});
thread_something.start();
after the 1st interval the label doesnt switch from break to recording
until 0:31 or 0:32 so it looks a little delayed.
If you want to display break from 0:20-0:29 and display "Recording" from 0:30-0:49, I think the if statement should change to InIntervalCounter >= WorkingInterval and InIntervalCounter >= TotalInterval, InIntervalCounter > WorkingInterval may cause the 1 second delay.
I'm building a racing game and I'm working on race times.
I try to build a system to start an instance of a timer with various options.
My little experience is putting me in crisis ... would some good soul want to help me?
This was the idea:
public class Timer {
public float counter;
public bool reset;
public string runtime = "--:--:--";
public string istant = "not istant";
public void startTimer()
{
/* inupdatealternative: counter += Time.deltaTime; */
if(reset == true)
{
counter = 0;
}
else
{
counter = Time.time;
}
var minutes = counter/60; // divide guitime by sixty (minutes)
var seconds = counter%60; // euclidean division (seconds)
var fraction = (counter * 100) % 100; // get fraction of seconds
runtime = string.Format ( "{0:00}:{1:00}:{2:000}", minutes, seconds, fraction);
Debug.Log("in Start: "+runtime);
}
public void resetTimer()
{
reset = true;
}
public string getTimerRuntime()
{
return runtime;
}
public string getTimerIstant()
{
istant = runtime;
return istant;
}
}
in update, for exemple:
var lapTimer = new Timer(); // create a new timer
if(Lap < Pilot.pilotlap )
{
lapTimer.startTimer();
Lap++
}
else if(Lap==Pilot.pilotlap)
{
timerLabel.text = lapTimer.getTimerIstant();
lapTimer.resetTimer();
lapTimer.startTimer();
}
in my head I'm sure someone has already dealt with it ... surely there will be something that manages the times and returns values in various ways: does it exist? or is there anyway how to make or build such a thing?
There is, it's called Stopwatch, it's THE class used in C# to use precise timers, and it's located in the System.Diagnostics namespace.
Using your Update() example, you can use it like this:
// Create a new stopwatch instance
// If the timer is used repeatedly, just instantiate one at start and re-use the same,
// to avoid garbage generation
Stopwatch lapTimer = new Stopwatch();
if(Lap < Pilot.pilotlap )
{
lapTimer.Start();
Lap++
}
else if(Lap==Pilot.pilotlap)
{
lapTimer.Stop();
// ElapsedMilliseconds returns exactly what it says, so you may need to format the value
// before passing it to the timerLabel.text
timerLabel.text = lapTimer.ElapsedMilliseconds.ToString();
lapTimer.Reset();
lapTimer.Start();
}
You can read about the class (its methods, fields and properties) here:
Stopwatch Class Documentation
You are doing a lot of unnecessary bool and local fields copiing and setting there. I would simply use something like
public class Timer
{
private float _startTime;
public bool IsRunning;
// you don't need an extra reset method
// simply pass it as a parameter
public void Start(bool reset = false)
{
if(IsRunning && !reset)
{
Debug.LogWarning("Timer is already running! If you wanted to restart consider passing true as parameter.");
return;
}
_startTime = Time.time;
Debug.Log("in Start: " + GetFormattedTime(_startTime));
IsRunning = true;
}
// depending what stop should do
// since this doesn't use any resources while running you could also simply
// only stick to the Start method and pass in true .. does basically the same
public void Stop()
{
IsRunning = false;
}
// I didn't see any difference between you two methods so I would simply use
public string GetCurrentTime()
{
if(!IsRunning)
{
Debug.LogWarning("Trying to get a time from a Timer that isn't running!");
return "--:--:---";
}
var timeDifference = Time.time - _startTime;
return GetFormattedTime(timeDifference);
}
private static string GetFormattedTime(float time)
{
// e.g. time = 74.6753
var minutes = Mathf.FloorToInt(time / 60f); // e.g. 1 (rounded down)
var seconds = Mathf.FloorToInt(time - 60f * minutes); // e.g. 14 (rounded down)
var fraction = Mathf.RoundToInt((time - seconds) * 1000f); // e.g. 676 (rounded down or up)
// Use a string interpolation for better readability
return $"{minutes:00}:{seconds:00}:{fraction:000}";
}
}
then in your Update you don't want to use
var lapTimer = new Timer(); // create a new timer
all the time since it would create a new timer and you wouldn't get any tracked time ... you rather would use it only once like
private Timer timer;
// just in case you want to keep track of needed times per lap
public List<string> lapTimes = new List<string>();
private void Awake()
{
timer = new Timer();
lapTimes.Clear();
}
private void Update()
{
...
if(Lap < Pilot.pilotlap)
{
timer.Start();
Lap++
}
else if(Lap == Pilot.pilotlap)
{
var currentTime = timer.GetCurrentTime();
timerLabel.text = currentTime;
lapTimes.Add(currentTime);
timer.Start(true)
}
...
}
Note that I don't know if this is all you have in Update or how you use it but you probably also do not want to (re)start the timer and count up the Lap every frame your conditions are true ... there should be more checks involved to make sure this can only be called once per lap ...
i wanted to create a program like this .
For every minute the time should be printed in the format of
h:m .For every 5 min it should print "break" this should continue for 24 hours ..
like this
0:0
0:1
0:2
0:3
0:4
break
0:6
0:7
0:8
0:9
break
0:11
.
.
.
23:59
i came with a program that solves it ..but i never used DateTime or any time function , i just used Thread.Sleep to dalay printing for 1 minute every time ...
i wanted to use some other method other than Thread.Sleep to solve it ...
so please guide me .. (sorry for my Bad english)
this is how i did with Thread.Sleep .
please provide me with any other solutions
using System;
using System.Threading;
class try22
{
public static void Main()
{
for(int i=0;i<24;i++)
{
for(int j=0;j<60;j++)
{
if(j%5 != 0 || (j == 0 && i == 0))
{
Thread.Sleep(20);
Console.WriteLine(i+":"+j);
}
else if(j%5 == 0 )
{
Thread.Sleep(20);
Console.WriteLine("break");
}
}
}
}
}
thanks guys i came up with the solution of using actual dates instead of array numbers in my problem
im getting weird errors with timer .. :( so i used thread.sleep itslef
using System;
using System.Threading;
class try22
{
public static void Main()
{
DateTime dt1 = new DateTime();
dt1 = DateTime.ParseExact("0:0", "H:m",null);
int cford=dt1.Day+1;
for (; dt1.Day!=cford; )
{
dt1 = addm(dt1);
Console.WriteLine(dts(dt1));
Thread.Sleep(60000);
}
}
public static string dts(DateTime dt)
{
string tmp = dt.ToString("H:m");
if (dt.Minute % 5 == 0)
return "BREAK";
else
return tmp;
}
public static DateTime addm(DateTime dt)
{
return dt.AddMinutes(1);
}
}
Which of these were you asked for?
Show the current time once per minute
Show the current time at the start of every minute like an alarm
Assuming 1, here's a couple of hints in the right direction (which should be helpful either way):
You can get the current date and time as a DateTime object using DateTime.Now
DateTime objects can return custom string output using .ToString("format").
Format is specified with a custom date and time format string. For example, to get the current hour in 24-hour time (without leading zeroes) you could use DateTime.Now.ToString("H").
As per the reference, you can include a string literal (unprocessed string) in your format. For example DateTime.Now.ToString("'Hour is: 'H") would return Hour is: 6
You can get the "minute" value of a DateTime object as an int using .Minute. For example, int minute = DateTime.Now.Minute;
If you want some code to run periodically, one way is to move it into its own method then setup a System.Threading.Timer like this:
void SomeMethod(object state) { /* DO STUFF HERE */ }
// Initialise the timer in your main() method
// As per MSDN for System.Threading.Timer, first number (0) is start delay.
// Second number (60000) is interval in milliseconds (60 seconds)
// This will cause SomeMethod to be called once every 60 seconds starting now.
Timer timer = new Timer(new TimerCallback(SomeMethod), null, 0, 60000);
You will need to stop your application exiting straight away after making the Timer (otherwise it will never get to run). One easy way to do this in a command line application is place a Console.Read() at the end of your Main() method which will wait for user input.
I have used Timer instead of Thread
class Program
{
private static System.Timers.Timer aTimer;
static int j = 0;
static int i = 0;
public static void Main()
{
// Create a timer with a Minute interval.
aTimer = new System.Timers.Timer(60000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 1 Minute (60000 milliseconds).
aTimer.Interval = 60000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.WriteLine(0 + ":" + 0);
Console.ReadLine();
}
// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
j++;
if (j == 60)
{
Console.WriteLine("break");
j = 1;
i = i + 1;
}
if (i == 24)
{
i = 0;
}
if (j % 5 != 0 || (j == 0))
{
Console.WriteLine(i + ":" + j);
}
else if (j % 5 == 0)
{
Console.WriteLine("break");
}
}
}
I am not sure weather you want to use actual System time to start with or just the time since program execution started. Solution i am posting uses time since program started.
using System;
using System.Collections.Generic;
using System.Text;
using System.Timers;
namespace ConsoleApplication1
{
class Program
{
TimeSpan tt;
static void Main(string[] args)
{
Program p = new Program();
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(p.run));
t.Start();
while (true) ;
}
void run()
{
tt=new TimeSpan(0,1,0);
//Timer interval decides when even will be fired.
Timer t = new Timer(60000);
t.AutoReset = true;
t.Elapsed += new ElapsedEventHandler(t_Elapsed);
t.Start();
}
public void t_Elapsed(object sender, EventArgs e)
{
if (tt.Minutes % 5 == 0)
Console.WriteLine("Break");
Console.WriteLine(tt.Hours.ToString()+":"+tt.Minutes.ToString());
tt = tt.Add(new TimeSpan(0, 1, 0));
}
}
}
I have a counter that counts up every 1 second and add 1 to an int.
Question
How can I format my string so the counter would look like this:
00:01:23
Instead of:
123
Things I've tried
Things I've tried so far:
for (int i = 0; i < 1; i++)
{
_Counter += 1;
labelUpTime.Text = _Counter.ToString();
}
My timer's interval is set to: 1000 (so it adds 1 every second).
I did read something about string.Format(""), but I don't know if it is applicable.
Thanks if you can guide me through this :D!
Use a TimeSpan:
_Counter += 1;
labelUpTime.Text = TimeSpan.FromSeconds(_Counter).ToString();
You could make it a TimeSpan (for that's what it is, a span of time), then format that:
labelUpTime.Text = TimeSpan.FromSeconds(_Counter).ToString();
Don't use a counter, and don't rely on the timer firing exactly every second. It won't. Do something like this.
class TimerTest
{
private DateTime _start = DateTime.Now;
private Timer _timer = new Timer(1000);
public TimerTest()
{
// (DateTime.Now - _start) returns a TimeSpan object
// Default TimeSpan.ToString() returns 00:00:00
_timer.Elapsed = (o, e) => labelUpTime.Text = (DateTime.Now - _start).ToString();
}
}
You can adjust the formatting with the TimeSpan.ToString method.
TimeSpan timer = new TimeSpan(0);
and on your interval:
timer += TimeSpan.FromSeconds(1);
Use timespan. To add a second use
mytimespan.Add(new TimespanFromSeconds(1));
Console.WriteLine(mytimespan); //Output in the form of xx:xx:xx
http://www.dotnetperls.com/timespan
it worked well for me
public TimeSpan ElapsedTimeFormatted
{
get
{
if (FinishedOn != null &&
StartedAt != null)
{
TimeSpan durationCount = new TimeSpan();
int hours = 0;
int minutes = 0;
int seconds = 0;
var times = Segments.Select(c => c.ElapsedTimeFormatted).ToList();
foreach (var time in times)
{
TimeSpan timeParse = TimeSpan.Parse(time);
hours = hours + (int)timeParse.Hours;
minutes = minutes + (int)timeParse.Minutes;
seconds = seconds + (int)timeParse.Seconds;
durationCount = new TimeSpan(hours, minutes, seconds);
}
return durationCount;
}
return new TimeSpan();
}
}