-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtypes.go
231 lines (187 loc) · 5.49 KB
/
types.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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
package isoduration
import (
"math"
"time"
)
// PeriodDuration is period duration marks
type PeriodDuration struct {
years float64
months float64
days float64
weeks float64
}
// TimeDuration is time duration marks
type TimeDuration struct {
hours float64
minutes float64
seconds float64
}
// Duration is basic duration structure
type Duration struct {
period *PeriodDuration
time *TimeDuration
multiplier float64
}
// NewDuration creates new *Duration based on time and period marks
func NewDuration(years, months, days, weeks, hours, minutes, seconds float64, isNegative bool) *Duration {
multiplier := float64(1)
if isNegative {
multiplier = -1
}
return &Duration{
period: &PeriodDuration{years, months, days, weeks},
time: &TimeDuration{hours, minutes, seconds},
multiplier: multiplier,
}
}
// NewFromTimeDuration creates new *Duration based on time.Duration
// Affect: This may have some rounding inaccuracies
func NewFromTimeDuration(t time.Duration) *Duration {
pd := new(PeriodDuration)
td := new(TimeDuration)
multiplier := float64(1)
if t < 0 {
multiplier = -1
t *= time.Duration(multiplier)
}
if t.Hours() >= DayHours*YearDays {
pd.years = math.Floor(t.Hours() / (DayHours * YearDays))
t -= time.Duration(float64(time.Hour) * pd.years * DayHours * YearDays)
}
if t.Hours() >= DayHours*MonthDays {
pd.months = math.Floor(t.Hours() / (DayHours * MonthDays))
t -= time.Duration(float64(time.Hour) * pd.months * DayHours * MonthDays)
}
if t.Hours() >= DayHours*WeekDays {
pd.weeks = math.Floor(t.Hours() / (DayHours * WeekDays))
t -= time.Duration(float64(time.Hour) * pd.weeks * DayHours * WeekDays)
}
if t.Hours() >= DayHours {
pd.days = math.Floor(t.Hours() / DayHours)
t -= time.Duration(float64(time.Hour) * pd.days * DayHours)
}
if t.Hours() >= 1 {
td.hours = math.Floor(t.Hours())
t -= time.Hour * time.Duration(td.hours)
}
if t.Minutes() >= 1 {
td.minutes = math.Floor(t.Minutes())
t -= time.Minute * time.Duration(td.minutes)
}
td.seconds = t.Seconds()
return &Duration{
period: pd,
time: td,
multiplier: multiplier,
}
}
// Years returns years from *PeriodDuration
func (d *Duration) Years() float64 {
return d.period.years * d.multiplier
}
// Months returns months from *PeriodDuration
func (d *Duration) Months() float64 {
return d.period.months * d.multiplier
}
// Weeks returns weeks from *PeriodDuration
func (d *Duration) Weeks() float64 {
return d.period.weeks * d.multiplier
}
// Days returns days from *PeriodDuration
func (d *Duration) Days() float64 {
return d.period.days * d.multiplier
}
// Hours returns hours from *TimeDuration
func (d *Duration) Hours() float64 {
return d.time.hours * d.multiplier
}
// Minutes returns minutes from *TimeDuration
func (d *Duration) Minutes() float64 {
return d.time.minutes * d.multiplier
}
// Seconds returns seconds from *TimeDuration
func (d *Duration) Seconds() float64 {
return d.time.seconds * d.multiplier
}
// ToTimeDuration turns *Duration into time.Duration
func (d *Duration) ToTimeDuration() time.Duration {
var timeDuration time.Duration
for _, v := range periodDesignators {
timeDuration += periodDesignatorsDef[v].get(d.period)
}
for _, v := range timeDesignators {
timeDuration += timeDesignatorsDef[v].get(d.time)
}
return timeDuration * time.Duration(d.multiplier)
}
// ToTimeDuration turns *Duration into a string in ISO 8601 duration format
func (d *Duration) String() string {
prefix := "P"
period := ""
tm := ""
for _, v := range periodDesignators {
if tmp := periodDesignatorsDef[v].string(d.period); tmp != "0"+string(v) {
period += tmp
}
}
for _, v := range timeDesignators {
if tmp := timeDesignatorsDef[v].string(d.time); tmp != "0"+string(v) {
tm += tmp
}
}
if d.multiplier == -1 && tm != "" && period != "" {
prefix = "-" + prefix
}
switch {
case tm == "" && period == "":
tm = "T0S"
case tm != "":
tm = "T" + tm
}
return prefix + period + tm
}
// FormatTimeDuration represents time.Duration as a string in ISO 8601 duration format
// Affect: This may have some rounding inaccuracies
func FormatTimeDuration(d time.Duration) string {
return NewFromTimeDuration(d).String()
}
// UnmarshalJSON designed to serialize a string in ISO 8601 duration format to *Duration, defined in user code via the json library
func (d *Duration) UnmarshalJSON(source []byte) error {
value := string(source)
if len(value) < 2 {
return IsNotIsoFormatError
}
if value == "null" {
return nil
}
if parsed, err := ParseDuration(value[1 : len(value)-1]); err == nil {
*d = *parsed
return nil
} else {
return err
}
}
// MarshalJSON designed to deserialize *Duration to a string in ISO 8601 duration format, defined in user code via the json library
func (d Duration) MarshalJSON() ([]byte, error) {
return []byte("\"" + d.String() + "\""), nil
}
// UnmarshalYAML designed to serialize a string in ISO 8601 duration format to *Duration, defined in user code via the gopkg.in/yaml.v3 library
func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {
var str string
if err := unmarshal(&str); err != nil {
return IsNotIsoFormatError
}
if str == "null" {
return nil
}
if parsed, err := ParseDuration(str); err == nil {
*d = *parsed
return nil
} else {
return err
}
}
// MarshalYAML designed to deserialize *Duration to a string in ISO 8601 duration format, defined in user code via the gopkg.in/yaml.v3 library
func (d Duration) MarshalYAML() (interface{}, error) {
return d.String(), nil
}