-
Notifications
You must be signed in to change notification settings - Fork 8
/
time.go
145 lines (130 loc) · 4.93 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
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package time
import (
"fmt"
"time"
)
const (
nanosPerSecond = 1000 * 1000 * 1000
secondsPerDay = 24 * 60 * 60
// Represent the unix epoch 1970-01-01 in terms of our epoch 0001-01-01, for
// easy conversions. Note that we use a proleptic Gregorian calendar; there
// is a leap year every 4 years, except for years divisible by 100, but
// including years divisible by 400.
unixEpoch = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay
minInt64 = -(1 << 63)
maxInt64 = ((1 << 63) - 1)
minGoDurationSec = minInt64 / nanosPerSecond
maxGoDurationSec = maxInt64 / nanosPerSecond
)
// TimeToNative is called by VDL for conversions from wire to native times.
func TimeToNative(wire Time, native *time.Time) error {
*native = time.Unix(wire.Seconds-unixEpoch, int64(wire.Nanos)).UTC()
return nil
}
// TimeFromNative is called by VDL for conversions from native to wire times.
func TimeFromNative(wire *Time, native time.Time) error {
wire.Seconds = native.Unix() + unixEpoch
wire.Nanos = int32(native.Nanosecond())
*wire = wire.Normalize()
return nil
}
// Normalize returns the normalized representation of x. It makes a best-effort
// attempt to clean up invalid values, e.g. if Nanos is outside the valid range,
// or the sign of Nanos doesn't match the sign of Seconds. The behavior is
// undefined for large invalid values, e.g. {int64max,int32max}.
func (x Time) Normalize() Time {
return Time(Duration(x).Normalize())
}
// Now returns the current time.
func Now() Time {
var t Time
TimeFromNative(&t, time.Now())
return t
}
// DurationToNative is called by VDL for conversions from wire to native
// durations.
func DurationToNative(wire Duration, native *time.Duration) error {
*native = 0
// Go represents duration as int64 nanoseconds, which has a much smaller range
// than VDL duration, so we catch these cases and return an error.
wire = wire.Normalize()
if wire.Seconds < minGoDurationSec ||
(wire.Seconds == minGoDurationSec && wire.Nanos < minInt64-minGoDurationSec*nanosPerSecond) ||
wire.Seconds > maxGoDurationSec ||
(wire.Seconds == maxGoDurationSec && wire.Nanos > maxInt64-maxGoDurationSec*nanosPerSecond) {
return fmt.Errorf("vdl duration %+v out of range of go duration", wire)
}
*native = time.Duration(wire.Seconds*nanosPerSecond + int64(wire.Nanos))
return nil
}
// DurationFromNative is called by VDL for conversions from native to wire
// durations.
func DurationFromNative(wire *Duration, native time.Duration) error {
wire.Seconds = int64(native / nanosPerSecond)
wire.Nanos = int32(native % nanosPerSecond)
return nil
}
// Normalize returns the normalized representation of x. It makes a best-effort
// attempt to clean up invalid values, e.g. if Nanos is outside the valid range,
// or the sign of Nanos doesn't match the sign of Seconds. The behavior is
// undefined for large invalid values, e.g. {int64max,int32max}.
func (x Duration) Normalize() Duration {
x.Seconds += int64(x.Nanos / nanosPerSecond)
x.Nanos = x.Nanos % nanosPerSecond
switch {
case x.Seconds < 0 && x.Nanos > 0:
x.Seconds += 1
x.Nanos -= nanosPerSecond
case x.Seconds > 0 && x.Nanos < 0:
x.Seconds -= 1
x.Nanos += nanosPerSecond
}
return x
}
// Deadline represents the deadline for an operation; it is the native
// representation for WireDeadline, and is automatically converted to/from
// WireDeadline during marshaling.
//
// Deadline represents the deadline as an absolute time, while WireDeadline
// represents the deadline as a relative duration from "now".
//
// To represent "no deadline", use the zero value for Deadline.
type Deadline struct {
// Time represents the deadline as an absolute point in time.
time.Time
}
// WireDeadlineToNative is called by VDL for conversions from wire to native
// deadlines.
func WireDeadlineToNative(wire WireDeadline, native *Deadline) error {
if wire.FromNow == 0 {
native.Time = time.Time{}
} else {
native.Time = time.Now().Add(wire.FromNow)
}
return nil
}
// WireDeadlineFromNative is called by VDL for conversions from native to wire
// deadlines.
func WireDeadlineFromNative(wire *WireDeadline, native Deadline) error {
if native.IsZero() {
wire.FromNow = 0
} else {
wire.FromNow = native.Sub(time.Now())
// Ensure that we never set FromNow=0, since that is special-cased to mean
// "no deadline".
//
// NOTE: A previous version of this code didn't include this special-case,
// and instead set the WireDeadline.NoDeadline field (which has now been
// removed) to indicate "no deadline". This means that there is a tiny
// chance that an old binary can send FromNow=0 to indicate "immediate
// deadline", which a new binary will interpret as "no deadline". As all
// binaries are updated to this new code, this problem will go away.
if wire.FromNow == 0 {
wire.FromNow = 1
}
}
return nil
}