forked from ChannelMeter/iso8601duration
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathduration.go
73 lines (64 loc) · 1.95 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
// Package duration provides a partial implementation of ISO8601 durations. (no months)
package duration
import (
"errors"
"fmt"
"regexp"
"strconv"
"text/template"
"time"
)
var (
// ErrBadFormat is returned when parsing fails
ErrBadFormat = errors.New("bad format string")
// ErrNoMonth is raised when a month is in the format string
ErrNoMonth = errors.New("no months allowed")
tmpl = template.Must(template.New("duration").Parse(`P{{if .Years}}{{.Years}}Y{{end}}{{if .Weeks}}{{.Weeks}}W{{end}}{{if .Days}}{{.Days}}D{{end}}{{if .HasTimePart}}T{{end }}{{if .Hours}}{{.Hours}}H{{end}}{{if .Minutes}}{{.Minutes}}M{{end}}{{if .Seconds}}{{.Seconds}}S{{end}}`))
full = regexp.MustCompile(`P((?P<year>\d+)Y)?((?P<month>\d+)M)?((?P<day>\d+)D)?(T((?P<hour>\d+)H)?((?P<minute>\d+)M)?((?P<second>\d+)S)?)?`)
week = regexp.MustCompile(`P((?P<week>\d+)W)`)
)
func ParseString(dur string) (*time.Duration, error) {
var duration time.Duration
var (
match []string
re *regexp.Regexp
)
if week.MatchString(dur) {
match = week.FindStringSubmatch(dur)
re = week
} else if full.MatchString(dur) {
match = full.FindStringSubmatch(dur)
re = full
} else {
return nil, ErrBadFormat
}
for i, name := range re.SubexpNames() {
part := match[i]
if i == 0 || name == "" || part == "" {
continue
}
val, err := strconv.Atoi(part)
if err != nil {
return nil, err
}
switch name {
case "year":
duration = duration + 24*365*time.Duration(val)*time.Hour
case "month":
return nil, ErrNoMonth
case "week":
duration = duration + 24*7*time.Duration(val)*time.Hour
case "day":
duration = duration + 24*time.Duration(val)*time.Hour
case "hour":
duration = duration + time.Duration(val)*time.Hour
case "minute":
duration = duration + time.Duration(val)*time.Minute
case "second":
duration = duration + time.Duration(val)*time.Second
default:
return nil, errors.New(fmt.Sprintf("unknown field %s", name))
}
}
return &duration, nil
}