Hello,

I have a little problem with a timer that I have set up. I use Thread.Sleep().

What I am trying to do, is to let a code run exactly when a new minute occurs on the millisecond (0 millisecond).
I have tried to set it up below and test it to write to file 4 times to see what the output is.

As seen the outputs are strange where the first result actually triggers on the 988:th millisecond before the next minute and the rest 4 milliseconds after the new minute.

//Minute,Second,Millisecond
32,59,988
34,0,4
35,0,4
36,0,4

Are there any better approach to do this to make it more accurate? I am not afraid to use microseconds in any
possible solution if that is a more accurate alternative.

      static readonly object lockObject = new object();
        private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            FileStream hr = new FileStream("C:/test.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
            StreamWriter file1 = new StreamWriter(hr); int count = 0;

            DateTime dt = DateTime.Now; int sleepTime = 0;
            while (true)
            {
                while (true)
                {
                    Thread.Sleep(900);

                   //Sleep to exactly next minute on the millisecond
                    dt = DateTime.Now;
                    if (dt.Second >= 50)
                    {
                        sleepTime = 60000 - ((dt.Second * 1000) + dt.Millisecond);
                        Thread.Sleep(sleepTime); break;
                    }
                }


                lock (lockObject)
                {
                    //We want this to react on the millisecond of the new minute
                    dt = DateTime.Now;
                    file1.WriteLine(dt.Minute + "," + dt.Second + "," + dt.Millisecond);

                    count++; if (count > 3) { break; }
                }
            }
            file1.Close(); hr.Close();
        }

Recommended Answers

All 6 Replies

This might be an easier way:

    public partial class Form3 : Form
    {
        static FileStream hr = new FileStream("C:\\test.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
        StreamWriter file1 = new StreamWriter(hr);
        DateTime dt;
        public Form3()
        {
            InitializeComponent();
            file1.AutoFlush = true;            
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            dt=DateTime.Now;
            if (dt.Millisecond == 0 & dt.Second==0)
            {
                label1.Text = dt.Hour + ":" + dt.Minute + ":" + dt.Second + ":" + dt.Millisecond;
                file1.WriteLine(label1.Text);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Interval = 1;
            timer1.Enabled = true;            
            timer1.Start();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            timer1.Stop();
        }

    }

There are 2 buttons and 1 label. Button1 starts the timer, and button2 stops it. I've set it up so that it waits until the even minute then starts printing to the file(echoed to the label), every minute on the minute.
Here's the output, very consistent. This is read from the hour, minute, second, and millisecond properties of dt, which gets set to datetime.now.

1:7:0:0
1:8:0:0
1:9:0:0
1:10:0:0

Because of the simplicity of the routines you can configure it in many different ways.

4 milliseconds seems about right to obtain a lock. You have to remember that code is going to take time to run.

Why do you need the time written to a file exactly on the millisecond?

tinstaafl:
Using the forms timer is subject to GUI updating. It only guarentees that the event will fire after the specified time, but not how long after. You're also running that code around 1000 times a second, wasteful of resources.

Like I said the simplicicty allows it to be configured however is necessary, but this does allow a code run exactly when a new minute occurs on the millisecond (0 millisecond). Like he said in his post. and the GUI is there only to facilitate running it and observing the results in real time. The whole thing can be fired without the GUI. In a console or even straight from a library.

Thanks alot, the timer seems very interesting. I have not actually used the timer before.

It seems to work very good. I did some changes to the code as you said also ofcourse, to not let it check datetime every millisecond like below where it checks every 1100 ms for a second >= 55 and then goes into interval of 1 millisecond to 0 second and >= 0 millisecond to be safe.
I beleive it could be a working approach.

        static FileStream hr = new FileStream("D:/test.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
        StreamWriter file1 = new StreamWriter(hr);
        DateTime dt;
        static readonly object lockobject = new object();
        private void timer1_Tick(object sender, EventArgs e) 
        {
            dt = DateTime.Now;
            if (dt.Second == 0 && dt.Millisecond >= 0)
            {
                lock (lockobject)
                {
                    label3.Text = dt.Hour + ":" + dt.Minute + ":" + dt.Second + ":" + dt.Millisecond;
                    file1.WriteLine(label3.Text);
                    timer1.Interval = 1100;
                }
            }
            else
            {
                if (dt.Second >= 55) { timer1.Interval = 1; }
            }               
        }


        private void button1_Click(object sender, EventArgs e)
        {
            file1.AutoFlush = true;

            timer1.Interval = 1100;
            timer1.Enabled = true; 
            timer1.Start();
        } 

Looks ok to me. Another approach is to start the timer at 1 millisecond until second and millisecond are 0(i.e. the start of a new mintute), then change to one minute(60000 ticks). That might be an even less strain on resources. I'm not sure though how accurate it would be over the long term. There might be some inaccuracies at the microsecond level that wouldn't show up for several hours. If the timing is very critical, it would have to be tested over the timeframe you'll need it to run. If inaccuracies are found resetting it once every hour would probably fix it.

That is very interesting what you said. I thought about something like that too but was also not sure how that would turn out in the very long run (microseconds etc).
Perheps it could be possible to reset the timer as you say after a certain timeinterval also.
I test around and see how it works. Thanks!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.