-
Notifications
You must be signed in to change notification settings - Fork 46
/
time.go
187 lines (164 loc) · 5.86 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
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
package weave
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/iov-one/weave/errors"
)
const (
// UNIX time value of 0001-01-01T00:00:00Z
minUnixTime = -62135596800
// UNIX time value of 9999-12-31T23:59:59Z
maxUnixTime = 253402300799
)
// UnixTime represents a point in time as POSIX time.
// This type comes in handy when dealing with protobuf messages. Instead of
// using Go's time.Time that includes nanoseconds use primitive int64 type and
// seconds precision. Some languages do not support nanoseconds precision
// anyway.
//
// When using in protobuf declaration, use gogoproto's typecasting
//
// int64 deadline = 1 [(gogoproto.casttype) = "github.com/iov-one/weave.UnixTime"];
//
type UnixTime int64
// Time returns a time.Time structure that represents the same moment in time.
func (t UnixTime) Time() time.Time {
return time.Unix(int64(t), 0)
}
// Add modifies this UNIX time by given duration. This is compatible with
// time.Time.Add method. Any duration value smaller than a second is ignored as
// it cannot be represented by the UnixTime type.
func (t UnixTime) Add(d time.Duration) UnixTime {
return t + UnixTime(d/time.Second)
}
// AsUnixTime converts given Time structure into its UNIX time representation.
// All time information more granular than a second is dropped as it cannot be
// represented by the UnixTime type.
func AsUnixTime(t time.Time) UnixTime {
return UnixTime(t.Unix())
}
// UnmarshalJSON supports unmarshaling both as time.Time and from a number.
// Usually a number is used as a representation of this time in JSON but it is
// convenient to use a string format in configurations (ie genesis file).
// Any granularity smaller than a second is dropped. For example, 1900
// milliseconds will be narrowed to 1 second.
func (t *UnixTime) UnmarshalJSON(raw []byte) error {
var n int64
if err := json.Unmarshal(raw, &n); err == nil {
unix := UnixTime(n)
if err := unix.Validate(); err != nil {
return err
}
*t = unix
return nil
}
var stdtime time.Time
if err := json.Unmarshal(raw, &stdtime); err == nil {
unix := UnixTime(stdtime.Unix())
if err := unix.Validate(); err != nil {
return err
}
*t = unix
return nil
}
return errors.Wrap(errors.ErrInput, "invalid time format")
}
// Validate returns an error if this time value is invalid.
func (t UnixTime) Validate() error {
if t < minUnixTime {
return errors.Wrap(errors.ErrState, "time must be an A.D. value")
}
if t > maxUnixTime {
return errors.Wrap(errors.ErrState, "time must be an before year 10000")
}
return nil
}
// String returns the usual string representation of this time as the time.Time
// structure would.
func (t UnixTime) String() string {
return t.Time().UTC().String()
}
// IsExpired returns true if given time is in the past as compared to the "now"
// as declared for the block. Expiration is inclusive, meaning that if current
// time is equal to the expiration time than this function returns true.
//
// This function panic if the block time is not provided in the context. This
// must never happen. The panic is here to prevent from broken setup to be
// processing data incorrectly.
func IsExpired(ctx Context, t UnixTime) bool {
blockNow, err := BlockTime(ctx)
if err != nil {
panic(fmt.Sprintf("%+v", err))
}
return t <= AsUnixTime(blockNow)
}
// InThePast returns true if given time is in the past compared to the current
// time as declared in the context. Context "now" should come from the block
// header.
// Keep in mind that this function is not inclusive of current time. It given
// time is equal to "now" then this function returns false.
// This function panic if the block time is not provided in the context. This
// must never happen. The panic is here to prevent from broken setup to be
// processing data incorrectly.
func InThePast(ctx context.Context, t time.Time) bool {
now, err := BlockTime(ctx)
if err != nil {
panic(fmt.Sprintf("%+v", err))
}
return t.Before(now)
}
// InTheFuture returns true if given time is in the future compared to the
// current time as declared in the context. Context "now" should come from the
// block header.
// Keep in mind that this function is not inclusive of current time. It given
// time is equal to "now" then this function returns false.
// This function panic if the block time is not provided in the context. This
// must never happen. The panic is here to prevent from broken setup to be
// processing data incorrectly.
func InTheFuture(ctx context.Context, t time.Time) bool {
now, err := BlockTime(ctx)
if err != nil {
panic(fmt.Sprintf("%+v", err))
}
return t.After(now)
}
// UnixDuration represents a time duration with granularity of a second. This
// type should be used mostly for protobuf message declarations.
type UnixDuration int32
// AsUnixDuration converts given Duration into UnixDuration. Because of the
// UnixDuration granularity precision of the value is narrowed to seconds.
func AsUnixDuration(d time.Duration) UnixDuration {
return UnixDuration(d / time.Second)
}
// Duration returns the time.Duration representation of this value.
func (d UnixDuration) Duration() time.Duration {
return time.Duration(d) * time.Second
}
// UnmarshalJSON loads JSON serialized representation into this value. JSON
// serialized value can be represented as both number of seconds and a human
// readable string with time unit as used by the time package.
func (d *UnixDuration) UnmarshalJSON(raw []byte) error {
var s string
if err := json.Unmarshal(raw, &s); err == nil {
dur, err := time.ParseDuration(s)
if err != nil {
return fmt.Errorf("invalid duration string: %s", err)
}
*d = AsUnixDuration(dur)
return nil
}
var n int32
if err := json.Unmarshal(raw, &n); err != nil {
return err
}
*d = UnixDuration(n)
return nil
}
func (d UnixDuration) MarshalJSON() ([]byte, error) {
return json.Marshal(int32(d))
}
func (d UnixDuration) String() string {
return d.Duration().String()
}