-
Notifications
You must be signed in to change notification settings - Fork 14
/
time.go
106 lines (91 loc) · 1.68 KB
/
time.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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
* Copyright (c) 2019 QLC Chain Team
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
package common
import (
"sort"
"sync/atomic"
"time"
"github.com/beevik/ntp"
)
var (
servers = []string{
"ntp.ntsc.ac.cn",
"time1.aliyun.com",
"time2.aliyun.com",
"time3.aliyun.com",
"time4.aliyun.com",
"time5.aliyun.com",
"time6.aliyun.com",
"time7.aliyun.com",
"time1.apple.com",
"time2.apple.com",
"time3.apple.com",
"time4.apple.com",
"time5.apple.com",
}
serverSize = len(servers)
availableIndex = 0
offset int64
times = 5
)
func init() {
go update()
go func() {
t := time.NewTicker(time.Minute)
for {
select {
case <-t.C:
update()
}
}
}()
}
func TimeNow() time.Time {
tmp := atomic.LoadInt64(&offset)
if tmp == 0 {
return time.Now()
} else {
return time.Now().Add(time.Duration(tmp))
}
}
func update() {
retry := 0
for {
if du, err := delta(servers[availableIndex]); err == nil {
atomic.StoreInt64(&offset, int64(du))
break
} else {
availableIndex++
availableIndex = availableIndex % serverSize
retry++
if retry > serverSize {
return
}
}
}
}
func delta(server string) (time.Duration, error) {
ds := make([]time.Duration, times)
for i := 0; i < times; i++ {
if response, err := ntp.Query(server); err == nil {
ds[i] = response.ClockOffset
} else {
return 0, err
}
}
sort.Slice(ds, func(i, j int) bool {
return ds[i] > ds[j]
})
return average(ds[1 : len(ds)-1]), nil
}
func average(ds []time.Duration) time.Duration {
total := time.Duration(0)
for _, v := range ds {
total += v
}
return total / time.Duration(len(ds))
}