-
Notifications
You must be signed in to change notification settings - Fork 0
/
null_time.go
154 lines (140 loc) · 3.47 KB
/
null_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
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
package epoch
import (
"database/sql/driver"
"encoding/json"
"fmt"
"reflect"
"time"
)
// NullTime is a nullable time.Time. It supports SQL and JSON serialization.
// It will marshal to null if null.
type NullTime struct {
Time Time
Valid bool
}
// Scan implements the Scanner interface.
func (t *NullTime) Scan(value interface{}) error {
var err error
switch x := value.(type) {
case time.Time:
t.Time = Time(x)
case nil:
t.Valid = false
return nil
default:
err = fmt.Errorf("null: cannot scan type %T into null.Time: %v", value, value)
}
t.Valid = err == nil
return err
}
// Value implements the driver Valuer interface.
func (t NullTime) Value() (driver.Value, error) {
if !t.Valid {
return nil, nil
}
return time.Time(t.Time), nil
}
// NewTime creates a new NullTime.
func NewNullTime(t time.Time, valid bool) NullTime {
return NullTime{
Time: Time(t),
Valid: valid,
}
}
// NullTimeFrom creates a new NullTime that will always be valid.
func NullTimeFrom(t time.Time) NullTime {
return NewNullTime(t, true)
}
// NullTimeFromPtr creates a new NullTime that will be null if t is nil.
func NullTimeFromPtr(t *time.Time) NullTime {
if t == nil {
return NewNullTime(time.Time{}, false)
}
return NewNullTime(*t, true)
}
// ValueOrZero returns the inner value if valid, otherwise zero.
func (t NullTime) ValueOrZero() time.Time {
if !t.Valid {
return time.Time{}
}
return time.Time(t.Time)
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this time is null.
func (t NullTime) MarshalJSON() ([]byte, error) {
if !t.Valid {
return []byte("null"), nil
}
return Time(t.Time).MarshalJSON()
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports string, object (e.g. pq.NullTime and friends)
// and null input.
func (t *NullTime) UnmarshalJSON(data []byte) error {
var err error
var v interface{}
if err = json.Unmarshal(data, &v); err != nil {
return err
}
switch x := v.(type) {
case float64:
et := Time(t.Time)
err = (&et).UnmarshalJSON(data)
t.Time = et
t.Valid = true
case string:
et := Time(t.Time)
err = (&et).UnmarshalJSON(data)
t.Time = et
t.Valid = true
case map[string]interface{}:
ti, tiOK := x["Time"].(string)
valid, validOK := x["Valid"].(bool)
if !tiOK || !validOK {
return fmt.Errorf(`json: unmarshalling object into Go value of type null.Time requires key "Time" to be of type string and key "Valid" to be of type bool; found %T and %T, respectively`, x["Time"], x["Valid"])
}
tt := time.Time(t.Time)
err = (&tt).UnmarshalText([]byte(ti))
t.Valid = valid
return err
case nil:
t.Valid = false
return nil
default:
err = fmt.Errorf("json: cannot unmarshal %v into Go value of type null.Time", reflect.TypeOf(v).Name())
}
t.Valid = err == nil
return err
}
func (t NullTime) MarshalText() ([]byte, error) {
if !t.Valid {
return []byte("null"), nil
}
return time.Time(t.Time).MarshalText()
}
func (t *NullTime) UnmarshalText(text []byte) error {
str := string(text)
if str == "" || str == "null" {
t.Valid = false
return nil
}
tt := time.Time(t.Time)
if err := (&tt).UnmarshalText(text); err != nil {
return err
}
t.Valid = true
return nil
}
// SetValid changes this NullTime's value and sets it to be non-null.
func (t *NullTime) SetValid(v time.Time) {
t.Time = Time(v)
t.Valid = true
}
// Ptr returns a pointer to this Time's value, or a nil pointer if this Time is null.
func (t NullTime) Ptr() *time.Time {
if !t.Valid {
return nil
}
tt := time.Time(t.Time)
return &tt
}