forked from fjl/go-couchdb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
time.go
113 lines (97 loc) · 2.85 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
107
108
109
110
111
112
113
package couchdb
import (
"fmt"
"time"
)
// ISOTimeFormat is the CouchDB time format
const (
TimeFormat = "2006-01-02T15:04:05.000Z"
TimeFormatShort = "2006-01-02T15:04:05Z"
TimeFormatWithZone = "2006-01-02T15:04:05.000-0700"
TimeFormatWithZoneShort = "2006-01-02T15:04:05-0700"
nullString = "null"
)
// TimeNow return a new CouchTime with current time
func TimeNow() Time {
return Time{Time: time.Now().UTC()}
}
// Time is used to decode from json times from CouchDB
type Time struct {
time.Time
}
// TimeWithZone allows times with a zone to be persisted to the database.
// Very useful storing documents in a local time.
type TimeWithZone struct {
time.Time
}
var nullTime time.Time
// UnmarshalJSON allows type to be passed to json.Unmarshal
func (t *Time) UnmarshalJSON(data []byte) error {
s := string(data)
if s == nullString {
return nil
}
s = s[1 : len(s)-1] // Remove quotes
var err error
*t, err = ParseTime(s)
return err
}
// MarshalJSON allows type to be passed to json.MarshalJSON
func (t Time) MarshalJSON() ([]byte, error) {
if t.IsNull() {
return []byte(nullString), nil
}
return []byte(`"` + t.String() + `"`), nil
}
// UnmarshalJSON allows type to be passed to json.Unmarshal
func (t *TimeWithZone) UnmarshalJSON(data []byte) error {
s := string(data)
if s == nullString {
return nil
}
s = s[1 : len(s)-1] // Remove quotes
var err error
*t, err = ParseTimeWithZone(s)
return err
}
// MarshalJSON allows type to be passed to json.MarshalJSON
func (t TimeWithZone) MarshalJSON() ([]byte, error) {
if t.IsNull() {
return []byte(nullString), nil
}
return []byte(`"` + t.String() + `"`), nil
}
// IsNull determines if a time value is set or not
func (t *Time) IsNull() bool {
return t.Equal(nullTime)
}
// IsNull determines if a time value is set or not
func (t *TimeWithZone) IsNull() bool {
return t.Equal(nullTime)
}
// ParseTime reads the provided ISO time string and creates a time object
func ParseTime(timeString string) (Time, error) {
// Short parsing has magic to read decimals (thanks Oleg!)
o, err := time.Parse(TimeFormatShort, timeString)
if err != nil {
return Time{nullTime}, fmt.Errorf("unable to parse time in UTC: %s", err)
}
return Time{o}, nil
}
// ParseTimeWithZone reads the provided ISO time string and creates a time object
// which references the zone.
func ParseTimeWithZone(timeString string) (TimeWithZone, error) {
o, err := time.Parse(TimeFormatWithZoneShort, timeString)
if err != nil {
return TimeWithZone{nullTime}, fmt.Errorf("unable to parse time with zone: %s", err)
}
return TimeWithZone{o}, nil
}
// String outputs back time in CouchDB format
func (t *Time) String() string {
return t.Format(TimeFormat)
}
// String provides the text version of the time with the zone included.
func (t *TimeWithZone) String() string {
return t.Format(TimeFormatWithZone)
}