About the accuracy of the time.Timer

func TestTicker(wg sync.WaitGroup) {
    calDuration := func(duration time.Duration) time.Duration {
        now := time.Now()
        return now.Truncate(duration).Add(duration).Sub(now)
    }
    go func(){
        t := time.NewTimer(calDuration(time.Minute))
        for {
            <-t.C
            fmt.Println(time.Now())
            t.Reset(calDuration(time.Minute))
        }
        wg.Done()
    }()
}

It sometimes happens to tick twice a minute as the duration may shrink. It’s really strange. Could somebody help me? Thanks

2018-07-19 14:36:00.003887996 +0800 CST m=+24.916092657
2018-07-19 14:37:00.002985076 +0800 CST m=+84.917119245
2018-07-19 14:38:00.001214551 +0800 CST m=+144.917278207
2018-07-19 14:39:00.000418561 +0800 CST m=+204.918411736
2018-07-19 14:39:59.999490194 +0800 CST m=+264.919412884
2018-07-19 14:40:00.000167519 +0800 CST m=+264.920090231
2018-07-19 14:40:59.99914446 +0800 CST m=+324.920996684
2018-07-19 14:41:00.000247228 +0800 CST m=+324.922099488

Note that time.Truncate rounds down, so instead of adding a full minute to the current time, you might be adding a little less. Does this make sense?

1 Like

Thanks for replying! So, what do you mean by “rounds down”? I don’t understand why it’s adding a little less. Could you help me through :)

Initially I thought you were asking why this is not sleeping for exactly a minute. My bad.

Let say that now is 12:15:30.91.

After calling Truncate you get 12:15:30.00.

Now you Add 1 minute: 12:16:30.00.

Now you Sub now: 00:00:59.09.

Since you are waking up < 1 ms too early, I doubt this is due to the overhead of the computation and the mechanism used to manage timers. If anything you would be waking up too late. I also doubt it’s because of the monotonic clock, but it’s possible. What kind of hardware is this running on?

Just out curiosity, what you do get if you use the time sent on the channel instead of time.Now()?

Sorry. I keep missing your question. My original answer applies to these two lines:

2018-07-19 14:39:59.999490194 +0800 CST m=+264.919412884
2018-07-19 14:40:00.000167519 +0800 CST m=+264.920090231

Notice when you do your computation when now is 14:39:59.99, truncate returns 14:39:59.00, you add a minute to get 14:40:00, substract now to get 00:00:00.001 and that’s for how long you wait, so you wake up again after one millisecond. The fact that you manage to squeeze in the call to Reset before the next millisecond elapses is astounding :slight_smile:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.