-
Notifications
You must be signed in to change notification settings - Fork 0
/
extent.go
156 lines (134 loc) Β· 3.83 KB
/
extent.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
package chrono
import (
"fmt"
"math"
)
// Extent represents a period of time measured in nanoseconds.
// The represented value is exactly equivalent to the standard library's time.Duration.
type Extent int64
// Common time-based durations relative to 1 nanosecond.
const (
Nanosecond Extent = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
// Nanoseconds returns the extent as an integer nanosecond count.
func (e Extent) Nanoseconds() int64 {
return int64(e)
}
// Microseconds returns the duration as a floating point number of microseconds.
func (e Extent) Microseconds() float64 {
micros := e / Microsecond
nsec := e % micros
return float64(micros) + float64(nsec)/1e3
}
// Milliseconds returns the duration as a floating point number of milliseconds.
func (e Extent) Milliseconds() float64 {
millis := e / Millisecond
nsec := e % millis
return float64(millis) + float64(nsec)/1e6
}
// Seconds returns the duration as a floating point number of seconds.
func (e Extent) Seconds() float64 {
secs := e / Second
nsec := e % secs
return float64(secs) + float64(nsec)/1e9
}
// Minutes returns the duration as a floating point number of minutes.
func (e Extent) Minutes() float64 {
mins := e / Minute
nsec := e % mins
return float64(mins) + float64(nsec)/(60*1e9)
}
// Hours returns the duration as a floating point number of hours.
func (e Extent) Hours() float64 {
hours := e / Hour
nsec := e % hours
return float64(hours) + float64(nsec)/(60*60*1e9)
}
// Units returns the whole numbers of hours, minutes, seconds, and nanosecond offset represented by e.
func (e Extent) Units() (hours, mins, secs, nsec int) {
return extentUnits(int64(e))
}
func extentUnits(e int64) (hours, mins, secs, nsec int) {
hours = int(e / oneHour)
mins = int(e/oneMinute) % 60
secs = int(e/oneSecond) % 60
nsec = int(e % oneSecond)
return
}
// Truncate returns the result of rounding e toward zero to a multiple of m.
func (e Extent) Truncate(m Extent) Extent {
return Extent(truncateExtent(int64(e), int64(m)))
}
func truncateExtent(e, m int64) int64 {
if m <= 0 {
return e
}
return e - e%m
}
// String returns a string formatted according to ISO 8601.
// It is equivalent to calling Format with no arguments.
func (e Extent) String() string {
return e.Format()
}
// Format the extent according to ISO 8601.
// Behaves the same as Duration.Format.
func (e Extent) Format(exclusive ...Designator) string {
abs := extentAbs(int64(e))
out, neg := formatDuration(abs/oneSecond, uint32(abs%oneSecond), e < 0, exclusive...)
out = "P" + out
if neg {
out = "-" + out
}
return out
}
// Parse the time portion of an ISO 8601 duration.
// Behaves the same as Duration.Parse.
func (e *Extent) Parse(s string) error {
_, _, _, _, secs, nsec, neg, err := parseDuration(s, false, true)
if err != nil {
return err
}
if err := checkExtentRange(secs, nsec, neg); err != nil {
return err
}
*e = Extent(secs*int64(Second) + int64(nsec))
if neg {
*e *= -1
}
return nil
}
func extentAbs(e int64) int64 {
if e < 0 {
return e * -1
}
return e
}
func checkExtentRange(secs int64, nsec uint32, neg bool) error {
if neg {
switch {
case -secs < minSeconds:
return fmt.Errorf("seconds underflow")
case -secs == minSeconds && nsec > uint32(maxNegNanos):
return fmt.Errorf("nanoseconds underflow")
}
} else {
switch {
case secs > maxSeconds:
return fmt.Errorf("seconds overflow")
case secs == maxSeconds && nsec > uint32(maxPosNanos):
return fmt.Errorf("nanoseconds overflow")
}
}
return nil
}
const (
minSeconds = int64(math.MinInt64) / int64(Second)
maxNegNanos = -(int64(math.MinInt64) % -minSeconds)
maxSeconds = int64(math.MaxInt64) / int64(Second)
maxPosNanos = int64(math.MaxInt64) % maxSeconds
)