-
Notifications
You must be signed in to change notification settings - Fork 1
/
duration.go
139 lines (127 loc) · 3.66 KB
/
duration.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
package multilogger
import (
"fmt"
"time"
"github.com/coveooss/multilogger/errors"
)
const (
day = 24 * time.Hour
week = 7 * day
month = 30 * day
year = 12 * month
)
var units = []struct {
delay time.Duration
divider time.Duration
unitShort string
unitLong string
}{
{year, year, "y", "year"},
{45 * day, month, "mo", "month"},
{10 * day, week, "w", "week"},
{day, day, "d", "day"},
{time.Hour, time.Hour, "h", "hour"},
{time.Minute, time.Minute, "m", "minute"},
{time.Second, time.Second, "s", "second"},
{time.Millisecond, time.Millisecond, "ms", "millisecond"},
{time.Microsecond, time.Microsecond, "µs", "microsecond"},
{time.Nanosecond, time.Nanosecond, "ns", "nanosecond"},
}
// DurationFormat represents the representation of a duration rendering format
type DurationFormat int
const (
// NativeFormat formats durations using the native golang duration format.
NativeFormat DurationFormat = iota
// PreciseFormat formats durations with precise unit for each segment 1d2h3m4s5ms6µs.
PreciseFormat
// ClassicFormat formats durations with higher units such as days, months, years,
// but use floating value bellow minutes as native golang format does.
ClassicFormat
)
// DurationFunc is the prototype used to represent a duration format function.
type DurationFunc func(time.Duration) string
// TryGetDurationFunc returns a function that can be used to format a duration.
func TryGetDurationFunc(format DurationFormat, rounded, longUnit bool) (DurationFunc, error) {
var (
minUnit, maxUnit time.Duration
)
switch format {
case PreciseFormat:
case ClassicFormat:
minUnit = time.Minute
case NativeFormat:
minUnit = time.Minute
maxUnit = day
default:
return func(d time.Duration) string { return fmt.Sprintf("%v", d) }, fmt.Errorf("unknown format %v", format)
}
return func(d time.Duration) string {
if rounded {
d = roundedDuration(d)
}
return formatDuration(d, minUnit, maxUnit, longUnit)
}, nil
}
// GetDurationFunc returns a function that can be used to format a duration.
func GetDurationFunc(format DurationFormat, rounded, longUnit bool) DurationFunc {
return errors.Must(TryGetDurationFunc(format, rounded, longUnit)).(DurationFunc)
}
func formatDuration(duration time.Duration, minUnit, maxUnit time.Duration, longUnit bool) (result string) {
for _, u := range units {
if u.delay >= maxUnit && maxUnit != 0 {
continue
}
if duration >= u.delay {
var value float64
if duration > minUnit {
div := duration / u.divider
value = float64(div)
duration -= div * u.divider
} else {
value = float64(duration) / float64(u.divider)
duration = 0
}
if longUnit {
if result != "" {
result += " "
}
unit := u.unitLong
if value >= 2 {
unit += "s"
}
result = fmt.Sprintf("%s%v %s", result, float64(value), unit)
} else {
result = fmt.Sprintf("%s%v%s", result, float64(value), u.unitShort)
}
}
}
if result == "" {
if longUnit {
result = "0 second"
} else {
result = "0s"
}
}
return
}
func roundedDuration(duration time.Duration) time.Duration {
switch {
case duration >= month:
return duration.Round(day)
case duration >= time.Hour:
return duration.Round(time.Minute)
case duration >= 5*time.Minute:
return duration.Round(time.Second)
case duration >= time.Minute:
return duration.Round(5 * time.Second)
case duration >= 10*time.Second:
return duration.Round(100 * time.Millisecond)
case duration >= time.Second:
return duration.Round(10 * time.Millisecond)
case duration >= time.Millisecond:
return duration.Round(10 * time.Microsecond)
case duration >= time.Microsecond:
return duration.Round(10 * time.Nanosecond)
}
return duration
}