-
Notifications
You must be signed in to change notification settings - Fork 1
/
utils.go
75 lines (64 loc) · 2.3 KB
/
utils.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
package myradio
import (
"errors"
"fmt"
"math"
"strconv"
"strings"
"time"
)
// parseShortTime parses times in MyRadio's 'DD/MM/YYYY HH:MM' local-time format.
// On success, it returns the equivalent time; else, it reports an error.
func parseShortTime(value string) (time.Time, error) {
return time.ParseInLocation("02/01/2006 15:04", value, time.Local)
}
// parseDuration parses durations in MyRadio's 'HH:MM:SS' format.
// On success, it returns the equivalent duration; else, it reports an error.
// Errors occur if the duration is not in the given format, or cannot be represented as a Duration.
// For a negative duration, give (-HH:MM:SS).
func parseDuration(value string) (dur time.Duration, err error) {
// @MattWindsor91:
// Previously, we relied on time.Parse to implement this.
// However, while convenient, this fails for durations that don't 'look' like times,
// eg. anything over 23:59:60.
if len(value) == 0 {
err = errors.New("parseDuration: duration string empty")
return
}
vs := strings.Split(value, ":")
if len(vs) != 3 {
err = fmt.Errorf("parseDuration: '%s' has %d sections but should have 3", value, len(vs))
return
}
// If the entire thing is prefixed by a sign, then we need to handle that carefully.
// This is because just treating the hours as negative fails if the hours part is -0!
sign := 1
if 0 < len(vs[0]) && vs[0][0] == '-' {
vs[0] = strings.Replace(vs[0], "-", "0", -1)
sign = -1
}
// Save us from repeating the same processing logic 3 times, at the cost of some efficiency when we fail.
parseBit := func(bit string, min, max int64) (val int64) {
// Short-circuit if previous parseBits failed.
if err != nil {
return
}
val, err = strconv.ParseInt(bit, 10, 64)
if err != nil {
return
}
// At this stage, val will contain the parsed value: this is just an additional sanity check.
if val < min || max < val {
err = fmt.Errorf("parseDuration: expected %d-%d, got %d", min, max, val)
}
return
}
h := parseBit(vs[0], math.MinInt64, math.MaxInt64)
m := parseBit(vs[1], 0, 59)
s := parseBit(vs[2], 0, 59) // This is a duration, so we don't need to worry about leap seconds.
if err != nil {
return
}
dur = time.Duration(sign) * ((time.Duration(h) * time.Hour) + (time.Duration(m) * time.Minute) + (time.Duration(s) * time.Second))
return
}