-
Notifications
You must be signed in to change notification settings - Fork 0
/
recurring.go
64 lines (58 loc) · 1.85 KB
/
recurring.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// Package recurring provides a ticker that fires at a specific time of day. It is modeled
// after time.Ticker in the standard library.
package recurring
import "time"
// Recurring holds a channel that delivers 'ticks' of a clock at a given time of day (UTC).
type Recurring struct {
C <-chan time.Time // The channel on which the ticks are delivered.
c chan time.Time
ticker *time.Ticker
quit chan interface{}
hour, min, sec, nsec int
}
func deadline(start time.Time, hour, min, sec, nsec int) time.Duration {
now := start.UTC()
nextTick := time.Date(now.Year(), now.Month(), now.Day(), hour, min, sec, nsec, time.UTC)
if nextTick.Before(now) || nextTick.Equal(now) {
nextTick = nextTick.Add(24 * time.Hour)
}
return nextTick.Sub(now)
}
// New returns a new Recurring containing a channel that will send the time at a given time of day (UTC)
// specified by the arguments. It will skip ticks if a receiver is slow enough (ie, more than 24 hours).
// Stop the Recurring to release associated resources.
func New(hour, min, sec, nsec int) *Recurring {
now := time.Now().UTC()
first := deadline(now, hour, min, sec, nsec)
r := &Recurring{
ticker: time.NewTicker(first),
quit: make(chan interface{}),
c: make(chan time.Time),
hour: hour,
min: min,
sec: sec,
nsec: nsec,
}
r.C = r.c
go r.wait()
return r
}
func (r *Recurring) wait() {
for {
select {
case t := <-r.ticker.C:
r.ticker.Stop()
r.c <- t
now := time.Now().UTC()
r.ticker = time.NewTicker(deadline(now, r.hour, r.min, r.sec, r.nsec))
case <-r.quit:
r.ticker.Stop()
return
}
}
}
// Stop turns off a Recurring. After Stop, no more ticks will be sent.
// Stop does not close the channel, to prevent a read from the channel succeeding incorrectly.
func (r *Recurring) Stop() {
close(r.quit)
}