/
datetime.go
293 lines (255 loc) · 8.56 KB
/
datetime.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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
package local
import (
"database/sql/driver"
"errors"
"fmt"
"time"
)
// DateTime represents a date-time without a timezone.
// Calculations on DateTime are performed using the standard
// library's time.Time type. For these calculations the
// timezone is UTC.
//
// DateTime is useful in situations where a date and time
// are specified, without reference to a timezone. Although not
// common, it can be useful. For example, a dose of medication
// may be scheduled for a particular date and time, regardless
// of the timezone that the patient is residing in at the time.
//
// Because DateTime does not specify a unique instant in
// time, it has never been necessary to specify to sub-second
// accuracy. For this reason DateTime only specifies the
// time to second accuracy. In actual fact, DateTime would
// probably be fine if it only specified to minute accuracy.
type DateTime struct {
t time.Time
}
// After reports whether the local date-time d is after e
func (dt DateTime) After(e DateTime) bool {
return dt.t.After(e.t)
}
// Before reports whether the local date-time d is before e
func (dt DateTime) Before(e DateTime) bool {
return dt.t.Before(e.t)
}
// Equal reports whether dt and e represent the same local date-time.
func (dt DateTime) Equal(e DateTime) bool {
return dt.t.Equal(e.t)
}
// IsZero reports whether dt represents the zero local date-time,
// Midnight, January 1, year 1.
func (dt DateTime) IsZero() bool {
return dt.t.IsZero()
}
// Date returns the year, month and day on which dt occurs.
func (dt DateTime) Date() (year int, month time.Month, day int) {
return dt.t.Date()
}
// Clock returns the hour, minute and second on which dt occurs.
func (dt DateTime) Clock() (hour int, minute int, second int) {
hour = dt.Hour()
minute = dt.Minute()
second = dt.Second()
return
}
// DateTime returns the year, month, day, hour minute, second and nanosecond on which dt occurs.
func (dt DateTime) DateTime() (year int, month time.Month, day int, hour int, minute int, second int) {
year, month, day = dt.t.Date()
hour, minute, second = dt.Clock()
return
}
// Unix returns d as a Unix time, the number of seconds elapsed
// since January 1, 1970 UTC to midnight of the date-time UTC.
func (dt DateTime) Unix() int64 {
return dt.t.Unix()
}
// Year returns the year in which dt occurs.
func (dt DateTime) Year() int {
return dt.t.Year()
}
// Month returns the month of the year specified by dt.
func (dt DateTime) Month() time.Month {
return dt.t.Month()
}
// Day returns the day of the month specified by dt.
func (dt DateTime) Day() int {
return dt.t.Day()
}
// Hour returns the hour specified by dt.
func (dt DateTime) Hour() int {
return dt.t.Hour()
}
// Minute returns the minute specified by dt.
func (dt DateTime) Minute() int {
return dt.t.Minute()
}
// Second returns the second specified by dt.
func (dt DateTime) Second() int {
return dt.t.Second()
}
// Weekday returns the day of the week specified by d.
func (dt DateTime) Weekday() time.Weekday {
return dt.t.Weekday()
}
// ISOWeek returns the ISO 8601 year and week number in which d occurs.
// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to
// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1
// of year n+1.
func (dt DateTime) ISOWeek() (year, week int) {
year, week = dt.t.ISOWeek()
return
}
// YearDay returns the day of the year specified by D, in the range [1,365] for non-leap years,
// and [1,366] in leap years.
func (dt DateTime) YearDay() int {
return dt.t.YearDay()
}
// Add returns the local date-time d + duration.
func (dt DateTime) Add(duration time.Duration) DateTime {
t := dt.t.Add(toSeconds(duration))
return DateTime{t: t}
}
// Sub returns the duration dt-e, which will be an integral number of seconds.
// If the result exceeds the maximum (or minimum) value that can be stored
// in a Duration, the maximum (or minimum) duration will be returned.
// To compute dt-duration, use dt.Add(-duration).
func (dt DateTime) Sub(e DateTime) time.Duration {
return dt.t.Sub(e.t)
}
// AddDate returns the local date-time corresponding to adding the given number of years,
// months, and days to t. For example, AddDate(-1, 2, 3) applied to January 1, 2011
// returns March 4, 2010.
//
// AddDate normalizes its result in the same way that Date does, so, for example,
// adding one month to October 31 yields December 1, the normalized form for November 31.
func (dt DateTime) AddDate(years int, months int, days int) DateTime {
t := dt.t.AddDate(years, months, days)
return DateTime{t: t}
}
// toDate converts the time.Time value into a DateTime.,
func toLocalDateTime(t time.Time) DateTime {
y, m, d := t.Date()
hour, minute, second := t.Clock()
return DateTimeFor(y, m, d, hour, minute, second)
}
// Now returns the current local date-time.
func Now() DateTime {
return toLocalDateTime(time.Now())
}
// DateTimeFor returns the DateTime corresponding to year, month, day, hour, minute and second.
//
// The month and day values may be outside their usual ranges
// and will be normalized during the conversion.
// For example, October 32 converts to November 1.
func DateTimeFor(year int, month time.Month, day int, hour int, minute int, second int) DateTime {
return DateTime{
t: time.Date(year, month, day, hour, minute, second, 0, time.UTC),
}
}
// DateTimeFromTime returns the DateTime corresponding to t.
func DateTimeFromTime(t time.Time) DateTime {
year, month, day := t.Date()
hour, minute, second := t.Clock()
return DateTimeFor(year, month, day, hour, minute, second)
}
// Format returns a textual representation of the time value formatted
// according to layout, which takes the same form as the standard library
// time package. Note that with a Date the reference time is
// Mon Jan 2 2006 15:04:05.
func (dt DateTime) Format(layout string) string {
return dt.t.Format(layout)
}
// String returns a string representation of d. The date
// format returned is compatible with ISO 8601: yyyy-mm-dd.
func (dt DateTime) String() string {
return localDateTimeString(dt)
}
// localDateTimeString returns the string representation of the date.
func localDateTimeString(dt DateTime) string {
year, month, day, hour, minute, second := dt.DateTime()
sign := ""
if year < 0 {
year = -year
sign = "-"
}
return fmt.Sprintf("%s%04d-%02d-%02dT%02d:%02d:%02d", sign, year, int(month), day, hour, minute, second)
}
// localDateQuotedString returns the string representation of the date in quotation marks.
func localDateQuotedString(dt DateTime) string {
return fmt.Sprintf(`"%s"`, localDateTimeString(dt))
}
// MarshalBinary implements the encoding.BinaryMarshaler interface.
func (dt DateTime) MarshalBinary() ([]byte, error) {
return dt.t.MarshalBinary()
}
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
func (dt *DateTime) UnmarshalBinary(data []byte) error {
var t time.Time
if err := t.UnmarshalBinary(data); err != nil {
return err
}
*dt = DateTimeFromTime(t)
return nil
}
// MarshalJSON implements the json.Marshaler interface.
// The date is a quoted string in an ISO 8601 format (yyyy-mm-dd).
func (dt DateTime) MarshalJSON() ([]byte, error) {
return []byte(localDateQuotedString(dt)), nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
// The date is expected to be a quoted string in an ISO 8601
// format (calendar or ordinal).
func (dt *DateTime) UnmarshalJSON(data []byte) (err error) {
s := string(data)
*dt, err = DateTimeParse(s)
return
}
// MarshalText implements the encoding.TextMarshaller interface.
// The date format is yyyy-mm-dd.
func (dt DateTime) MarshalText() ([]byte, error) {
return []byte(localDateTimeString(dt)), nil
}
// UnmarshalText implements the encoding.TextUnmarshaller interface.
// The date is expected to an ISO 8601 format (calendar or ordinal).
func (dt *DateTime) UnmarshalText(data []byte) (err error) {
s := string(data)
*dt, err = DateTimeParse(s)
return
}
// Scan implements the sql.Scanner interface.
func (dt *DateTime) Scan(src interface{}) error {
switch v := src.(type) {
case string:
{
d1, err := DateTimeParse(v)
if err != nil {
return err
}
*dt = d1
}
case []byte:
{
d1, err := DateTimeParse(string(v))
if err != nil {
return err
}
*dt = d1
}
case time.Time:
{
d1 := DateTimeFromTime(v)
*dt = d1
}
case nil:
*dt = DateTime{}
default:
return errors.New("cannot convert to local.DateTime")
}
return nil
}
// Value implements the driver.Valuer interface.
func (dt DateTime) Value() (driver.Value, error) {
year, month, day := dt.Date()
hour, minute, second := dt.Clock()
return time.Date(year, month, day, hour, minute, second, 0, time.UTC), nil
}