This repository has been archived by the owner on Aug 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utc.go
211 lines (181 loc) · 5.09 KB
/
utc.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Package utc is a lightweit time struct stripped of its timezone awareness
//
// Known limitations : dates before the year ~1678 cannot be represented with this time struct,
// but most of the time we can live with it.
package utc
import (
"math"
"strconv"
"time"
)
const day = time.Hour * 24
// UTC is the number of nanoseconds elapsed since January 1, 1970 UTC.
// The result is undefined if the Unix time in nanoseconds cannot be represented by an int64.
// Note that this means the result of calling UnixNano on the zero Time is undefined.
type UTC int64
// Convert converts a Time struct into UTC
func Convert(t time.Time) UTC {
return UTC(t.UTC().UnixNano())
}
// Now returns the current time.
func Now() UTC {
return Convert(time.Now())
}
// In returns the current time + d
func In(d time.Duration) UTC {
return Convert(time.Now().Add(d))
}
// Max returns the latest time
func Max(l ...UTC) UTC {
if len(l) == 0 {
return UTC(0)
}
max := UTC(math.MinInt64)
for _, t := range l {
if t > max {
max = t
}
}
return max
}
// Min returns the earliest time
func Min(l ...UTC) UTC {
if len(l) == 0 {
return UTC(0)
}
min := UTC(math.MaxInt64)
for _, t := range l {
if t < min {
min = t
}
}
return min
}
// MustParse is like Parse, but it panics when there is a parsing error.
// It simplifies safe initialisation of UTC values.
func MustParse(s string) UTC {
t, err := Parse(s)
if err != nil {
panic(err)
}
return t
}
// Parse parses a formatted string as defined by the RFC3339 and returns the time value it represents.
//
// Note: If it returns a time.ParseError with "second out of range" when the second is equal to 60,
// it means it is a leap second. The go time package does not handle leap seconds.
// More info: https://github.com/golang/go/issues/8728
// However, chances are so slim that it does not worth handling that scenario (for now)
func Parse(s string) (UTC, error) {
t, err := time.Parse(time.RFC3339Nano, s)
if err != nil {
return 0, err
}
return Convert(t), nil
}
// IsZero reports whether t represents the zero time instant,
// January 1, year 1, 00:00:00 UTC.
func (t UTC) IsZero() bool {
return t == 0
}
// Time converts the UTC type to the standard time.Time
func (t UTC) Time() time.Time {
return time.Unix(0, int64(t)).UTC()
}
// String returns the default UTC string representation
func (t UTC) String() string {
return t.RFC3339Nano()
}
// RFC3339 returns a string representation in RFC3339 format
func (t UTC) RFC3339() string {
return t.Time().Format(time.RFC3339)
}
// RFC3339Nano returns a string representation in RFC3339 format with nanoseconds
func (t UTC) RFC3339Nano() string {
return t.Time().Format(time.RFC3339Nano)
}
// Add returns the time t+d
func (t UTC) Add(d time.Duration) UTC {
return t + UTC(d)
}
// Sub returns the time t-d
func (t UTC) Sub(d time.Duration) UTC {
return t - UTC(d)
}
// Distance returns the duration t - u.
// If the result exceeds the maximum (or minimum) value that can be stored in a Duration,
// the maximum (or minimum) duration will be returned.
func (t UTC) Distance(u UTC) time.Duration {
return time.Duration(t) - time.Duration(u)
}
// BeginningOfDay returns a new UTC with its time reset to midnight
func (t UTC) BeginningOfDay() UTC {
return t.Floor(day)
}
// EndOfDay returns a new UTC with its time set to the last nanosecond of the day
func (t UTC) EndOfDay() UTC {
return t.Floor(day) + UTC(day-time.Nanosecond)
}
// Floor rounds date down to the given precision
func (t UTC) Floor(prec time.Duration) UTC {
return t - abs(t)%UTC(prec)
}
// Ceil rounds date up to the given precision
func (t UTC) Ceil(prec time.Duration) UTC {
rem := abs(t) % UTC(prec)
if rem > 0 {
return t - rem + UTC(prec)
}
return t - rem
}
// GobEncode implements the gob.GobEncoder interface.
func (t UTC) GobEncode() ([]byte, error) {
s := strconv.FormatInt(int64(t), 10)
return []byte(s), nil
}
// GobDecode implements the gob.GobDecoder interface.
func (t *UTC) GobDecode(data []byte) error {
i, err := strconv.ParseInt(string(data), 10, 64)
if err != nil {
return err
}
v := UTC(i)
*t = v
return nil
}
// MarshalJSON implements the json.Marshaler interface.
// The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
func (t UTC) MarshalJSON() ([]byte, error) {
return t.Time().MarshalJSON()
}
// UnmarshalJSON implements the json.Unmarshaler interface.
// The time is expected to be a quoted string in RFC 3339 format.
func (t *UTC) UnmarshalJSON(data []byte) error {
a := t.Time()
if err := a.UnmarshalJSON(data); err != nil {
return err
}
*t = Convert(a)
return nil
}
// MarshalText implements the encoding.TextMarshaler interface
// It uses the default string representation from String()
func (t UTC) MarshalText() (text []byte, err error) {
return []byte(t.String()), nil
}
// UnmarshalText implements the encoding.TextUnmarshaler interface
// It uses the default layout - RFC3339 with nanoseconds
func (t *UTC) UnmarshalText(text []byte) error {
u, err := Parse(string(text))
if err != nil {
return err
}
*t = u
return nil
}
func abs(t UTC) UTC {
if t < 0 {
return t * -1
}
return t
}