-
Notifications
You must be signed in to change notification settings - Fork 39
/
time.go
95 lines (77 loc) · 2.14 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
package notion
import (
"encoding/json"
"errors"
"time"
)
// Length of a date string, e.g. `2006-01-02`.
const dateLength = 10
// DateTimeFormat is used when calling time.Parse, using RFC3339 with microsecond
// precision, which is what the Notion API returns in JSON response data.
const DateTimeFormat = "2006-01-02T15:04:05.999Z07:00"
// DateTime represents a Notion date property with optional time.
type DateTime struct {
time.Time
hasTime bool
}
// ParseDateTime parses an RFC3339 formatted string with optional time.
func ParseDateTime(value string) (DateTime, error) {
if len(value) > len(DateTimeFormat) {
return DateTime{}, errors.New("invalid datetime string")
}
t, err := time.Parse(DateTimeFormat[:len(value)], value)
if err != nil {
return DateTime{}, err
}
dt := DateTime{
Time: t,
hasTime: len(value) > dateLength,
}
return dt, nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (dt *DateTime) UnmarshalJSON(b []byte) error {
if len(b) < 2 {
return errors.New("invalid datetime string")
}
parsed, err := ParseDateTime(string(b[1 : len(b)-1]))
if err != nil {
return err
}
*dt = parsed
return nil
}
// MarshalJSON implements json.Marshaler. It returns an RFC399 formatted string,
// using microsecond precision ()
func (dt DateTime) MarshalJSON() ([]byte, error) {
if dt.hasTime {
return json.Marshal(dt.Time)
}
return []byte(`"` + dt.Time.Format(DateTimeFormat[:dateLength]) + `"`), nil
}
// NewDateTime returns a new DateTime. If `haseTime` is true, time is included
// when encoding to JSON.
func NewDateTime(t time.Time, hasTime bool) DateTime {
var tt time.Time
if hasTime {
tt = t
} else {
tt = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.UTC)
}
return DateTime{
Time: tt,
hasTime: hasTime,
}
}
// HasTime returns true if the datetime was parsed from a string that included time.
func (dt *DateTime) HasTime() bool {
return dt.hasTime
}
// Equal returns true if both DateTime values have equal underlying time.Time and
// hasTime fields.
func (dt DateTime) Equal(value DateTime) bool {
if !dt.Time.Equal(value.Time) {
return false
}
return dt.hasTime == value.hasTime
}