-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdatemath_parser.go
133 lines (120 loc) · 3.07 KB
/
datemath_parser.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
package datemath_parser
import (
"fmt"
"regexp"
"strconv"
"strings"
"time"
"github.com/araddon/dateparse"
"github.com/vjeantet/jodaTime"
)
var durRegexp = regexp.MustCompile(`([\+-]\d*|\/)(y|M|w|d|h|H|m|s)`)
var emptyTime = time.Unix(0, 0)
var units = map[string]time.Duration{
"y": time.Hour * 365 * 24,
"M": time.Hour * 30 * 24,
"w": time.Hour * 7 * 24,
"d": time.Hour * 24,
"h": time.Hour,
"H": time.Hour,
"m": time.Minute,
"s": time.Second,
}
type DateMathParser struct {
Formats []string
TimeZone *time.Location
}
func NewDateMathParser(opts ...DateMathParserOption) (*DateMathParser, error) {
var p = &DateMathParser{
TimeZone: time.UTC,
}
for _, opt := range opts {
if err := opt(p); err != nil {
return nil, err
}
}
return p, nil
}
func (p *DateMathParser) Parse(expr string) (time.Time, error) {
var res time.Time
var dur = ""
if len(expr) >= 3 && expr[0:3] == "now" {
dur = expr[3:]
res = time.Now()
} else {
var sep = strings.Index(expr, "||")
var err error
if sep == -1 {
dur = ""
if res, err = p.parseTime(expr); err != nil {
return emptyTime, err
}
} else {
dur = expr[sep+2:]
if res, err = p.parseTime(expr[:sep]); err != nil {
return emptyTime, err
}
}
}
res = res.UTC()
if dur == "" {
return res, nil
} else {
return p.evalDur(dur, res)
}
}
func (p *DateMathParser) parseTime(expr string) (time.Time, error) {
if len(p.Formats) != 0 {
for _, format := range p.Formats {
if format == "epoch_second" {
if sec, err := strconv.ParseInt(expr, 10, 64); err != nil {
continue
} else if len(expr) <= 10 { // 秒的精度是10位
return time.Unix(sec, 0), nil
}
} else if format == "epoch_millis" {
if millis, err := strconv.ParseInt(expr, 10, 64); err != nil {
continue
} else if len(expr) <= 13 { // 毫秒的精度是13位
return time.Unix(millis/1000, millis%1000), nil
}
} else {
if tim, err := p.parseFormat(expr, format); err == nil {
return tim, nil
}
}
}
return emptyTime, fmt.Errorf("failed to parse time, expr: %s, format: %+v", expr, p.Formats)
} else {
return p.parseAny(expr)
}
}
func (p *DateMathParser) parseFormat(expr, format string) (time.Time, error) {
return jodaTime.ParseInLocation(format, expr, p.TimeZone.String())
}
func (p *DateMathParser) parseAny(expr string) (time.Time, error) {
return dateparse.ParseIn(expr, p.TimeZone)
}
func (p *DateMathParser) evalDur(dur string, tim time.Time) (time.Time, error) {
var res = tim
var allMatch = durRegexp.FindAllStringSubmatch(dur, -1)
if len(allMatch) == 0 {
return emptyTime, fmt.Errorf(`expect match expression: ([\+-]\d*|\/)(y|M|w|d|h|H|m|s)`)
}
for _, s := range allMatch {
if s[1] == "/" {
res = res.Round(units[s[2]])
} else {
var d int
if s[1] == "-" {
d = -1
} else if s[1] == "+" {
d = 1
} else {
d, _ = strconv.Atoi(s[1])
}
res = res.Add(time.Duration(d) * units[s[2]])
}
}
return res, nil
}