-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathduration.go
More file actions
139 lines (118 loc) · 2.77 KB
/
duration.go
File metadata and controls
139 lines (118 loc) · 2.77 KB
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 bigdur parses large durations.
// In addition to units supported by the standard library,
// It supports:
//
// - d for 24 hours
//
// - mo for 30 days
//
// - y for 12 months
package bigdur
import (
"bytes"
"strconv"
"time"
"github.com/pkg/errors"
)
// Duration represents an interval of time.
type Duration uint64
// Parse parses a Duration.
func Parse(str string) (Duration, error) {
var (
dur Duration
parsingNum = true
numStart int
numEnd int
i int
r rune
)
finishPart := func() error {
c, err := strconv.ParseFloat(str[numStart:numEnd], 64)
if err != nil {
return errors.Wrap(err, "failed to parse coefficient")
}
if c < 0 {
return errors.New("negative durations are invalid")
}
u, err := parseDurationUnit(str[numEnd:i])
if err != nil {
return errors.Wrapf(err, "failed to parse unit %q", str[numEnd:i])
}
dur += Duration(c * float64(u.Multiplier))
numStart, numEnd = i, i
return nil
}
for i, r = range str {
// fmt.Printf("parsing %c, i %v\n", r, i)
// check if numeric
if (r >= '0' && r <= '9') || r == '.' {
if !parsingNum {
// fmt.Printf("1\n")
if err := finishPart(); err != nil {
return 0, err
}
}
parsingNum = true
continue
}
if parsingNum {
numEnd = i
parsingNum = false
}
}
if numEnd > numStart {
i = len(str)
if err := finishPart(); err != nil {
return 0, err
}
}
return dur, nil
}
// Duration converts into a standard library time.Duration.
func (d Duration) Std() time.Duration {
return time.Duration(time.Second * time.Duration(d))
}
// String returns a human-readable representation of Duration.
func (d Duration) String() string {
out := &bytes.Buffer{}
var (
co Duration
)
if d == Duration(0) {
return "0s"
}
for i := len(durationUnits) - 1; i >= 0 && d > 0; i-- {
// fmt.Printf("d:%v %v:%v \n", uint64(d), durationUnits[i].Unit, uint64(durationUnits[i].Multiplier))
if d >= durationUnits[i].Multiplier {
co = d / durationUnits[i].Multiplier
out.WriteString(strconv.FormatUint(uint64(co), 10))
out.WriteString(durationUnits[i].Unit)
d -= co * durationUnits[i].Multiplier
}
}
return out.String()
}
type durationUnit struct {
Unit string
Multiplier Duration
}
// Duration units
var (
durationUnits = [...]durationUnit{
{Unit: "s", Multiplier: 1},
{Unit: "m", Multiplier: 60},
{Unit: "h", Multiplier: 60 * 60},
{Unit: "d", Multiplier: 60 * 60 * 24},
{Unit: "w", Multiplier: 60 * 60 * 24 * 7},
{Unit: "mo", Multiplier: 60 * 60 * 24 * 7 * 30},
{Unit: "y", Multiplier: 60 * 60 * 24 * 7 * 30 * 12},
}
)
func parseDurationUnit(unit string) (durationUnit, error) {
for _, du := range durationUnits {
if du.Unit == unit {
return du, nil
}
}
return durationUnit{}, errors.New("no unit found")
}