forked from guregu/null
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtimestamp.go
More file actions
142 lines (126 loc) · 3.69 KB
/
timestamp.go
File metadata and controls
142 lines (126 loc) · 3.69 KB
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
package null
import (
"bytes"
"database/sql"
"database/sql/driver"
"encoding/json"
"fmt"
"strconv"
"time"
)
// Timestamp is a nullable time.Time. It supports SQL and JSON serialization.
// It will marshal to null if null.
type Timestamp struct {
sql.NullTime
}
// Value implements the driver Valuer interface.
func (t Timestamp) Value() (driver.Value, error) {
if !t.Valid {
return nil, nil
}
return t.Time, nil
}
// NewTimestamp creates a new Timestamp.
func NewTimestamp(t time.Time, valid bool) Timestamp {
return Timestamp{
NullTime: sql.NullTime{
Time: t,
Valid: valid,
},
}
}
// TimestampFrom creates a new Timestamp that will always be valid.
func TimestampFrom(t time.Time) Timestamp {
return NewTimestamp(t, true)
}
// TimestampFromPtr creates a new Timestamp that will be null if t is nil.
func TimestampFromPtr(t *time.Time) Timestamp {
if t == nil {
return NewTimestamp(time.Time{}, false)
}
return NewTimestamp(*t, true)
}
// ValueOrZero returns the inner value if valid, otherwise zero.
func (t Timestamp) ValueOrZero() time.Time {
if !t.Valid {
return time.Time{}
}
return t.Time
}
// MarshalJSON implements json.Marshaler.
// It will encode null if this timestamp is null.
func (t Timestamp) MarshalJSON() ([]byte, error) {
if !t.Valid {
return []byte("null"), nil
}
return []byte(strconv.FormatInt(t.Time.Unix(), 10)), nil
}
// UnmarshalJSON implements json.Unmarshaler.
// It supports int64 and null input.
func (t *Timestamp) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, nullBytes) {
t.Valid = false
return nil
}
var v int64
if err := json.Unmarshal(data, &v); err != nil {
return fmt.Errorf("null: couldn't unmarshal JSON: %w", err)
}
t.Time = time.Unix(v, 0)
t.Valid = true
return nil
}
// MarshalText implements encoding.TextMarshaler.
// It returns an empty string if invalid, otherwise int64.
func (t Timestamp) MarshalText() ([]byte, error) {
if !t.Valid {
return []byte{}, nil
}
return []byte(strconv.FormatInt(t.Time.Unix(), 10)), nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
// It will unmarshal to a null int64 Unix timestamp to time.Time if the input is a blank or not an time.Time.
func (t *Timestamp) UnmarshalText(text []byte) error {
str := string(text)
// allowing "null" is for backwards compatibility with v3
if str == "" || str == "null" {
t.Valid = false
return nil
}
v, err := strconv.ParseInt(str, 0, 64)
if err != nil {
return fmt.Errorf("null: couldn't unmarshal text: %w", err)
}
t.Time = time.Unix(v, 0)
t.Valid = true
return nil
}
// SetValid changes this Timestamp's value and sets it to be non-null.
func (t *Timestamp) SetValid(v time.Time) {
t.Time = v
t.Valid = true
}
// Ptr returns a pointer to this Timestamp's value, or a nil pointer if this Time is null.
func (t Timestamp) Ptr() *time.Time {
if !t.Valid {
return nil
}
return &t.Time
}
// IsZero returns true for invalid Times, hopefully for future omitempty support.
// A non-null Time with a zero value will not be considered zero.
func (t Timestamp) IsZero() bool {
return !t.Valid
}
// Equal returns true if both Timestamp objects encode the same time or are both null.
// Two times can be equal even if they are in different locations.
// For example, 6:00 +0200 CEST and 4:00 UTC are Equal.
func (t Timestamp) Equal(other Timestamp) bool {
return t.Valid == other.Valid && (!t.Valid || t.Time.Equal(other.Time))
}
// ExactEqual returns true if both Timestamp objects are equal or both null.
// ExactEqual returns false for times that are in different locations or
// have a different monotonic clock reading.
func (t Timestamp) ExactEqual(other Timestamp) bool {
return t.Valid == other.Valid && (!t.Valid || t.Time == other.Time)
}