-
Notifications
You must be signed in to change notification settings - Fork 0
/
time.go
116 lines (103 loc) · 3.02 KB
/
time.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
package swiss
import (
"errors"
"regexp"
"strconv"
"strings"
"time"
)
var ErrTimeFormat = errors.New("unrecognized time format")
var (
datePatterns = map[string]string{
"yesterday": `yesterday`,
"today": `today`,
"tomorrow": `tomorrow`,
"minutes_ago": `(\d+)\s*min(?:ute)?s?\s*ago`,
"minutes_from": `in\s*(\d+)\s*min(?:ute)?s?`,
"hours_ago": `(\d+)\s*hour(?:s)?\s*ago`,
"hours_from": `in\s*(\d+)\s*hour(?:s)?`,
"days_ago": `(\d+)\s*day(?:s)?\s*ago`,
"days_from": `in\s*(\d+)\s*day(?:s)?`,
"weeks_ago": `(\d+)\s*week(?:s)?\s*ago`,
"weeks_from": `in\s*(\d+)\s*week(?:s)?`,
"months_ago": `(\d+)\s*month(?:s)?\s*ago`,
"months_from": `in\s*(\d+)\s*month(?:s)?`,
"years_ago": `(\d+)\s*year(?:s)?\s*ago`,
"years_from": `in\s*(\d+)\s*year(?:s)?`,
}
timeReg = regexp.MustCompile(`at\s*(\d{1,2})(:(\d{2}))?\s*(am|pm)?`)
)
// TimeFromHumanReadable will take in a string and try to parse out a time.
func TimeFromHumanReadable(s string) (time.Time, error) {
s = strings.ToLower(s) // to lower so we don't need complicated regex
now := time.Now().UTC()
builtTime := time.Time{}
for unit, pattern := range datePatterns {
re := regexp.MustCompile(pattern)
matches := re.FindStringSubmatch(s)
if len(matches) > 0 {
switch unit {
case "yesterday":
builtTime = now.AddDate(0, 0, -1)
case "tomorrow":
builtTime = now.AddDate(0, 0, 1)
default:
amount, err := strconv.Atoi(matches[1])
if err != nil {
return time.Time{}, err
}
switch unit {
case "minutes_ago":
builtTime = now.Add(time.Duration(-amount) * time.Minute)
case "minutes_from":
builtTime = now.Add(time.Duration(amount) * time.Minute)
case "hours_ago":
builtTime = now.Add(time.Duration(-amount) * time.Hour)
case "hours_from":
builtTime = now.Add(time.Duration(amount) * time.Hour)
case "days_ago":
builtTime = now.AddDate(0, 0, -amount)
case "days_from":
builtTime = now.AddDate(0, 0, amount)
case "weeks_ago":
builtTime = now.AddDate(0, 0, -amount*7)
case "weeks_from":
builtTime = now.AddDate(0, 0, amount*7)
case "months_ago":
builtTime = now.AddDate(0, -amount, 0)
case "months_from":
builtTime = now.AddDate(0, amount, 0)
case "years_ago":
builtTime = now.AddDate(-amount, 0, 0)
case "years_from":
builtTime = now.AddDate(amount, 0, 0)
}
}
}
}
if matches := timeReg.FindStringSubmatch(s); len(matches) > 0 {
hour, err := strconv.Atoi(matches[1])
if err != nil {
return time.Time{}, err
}
minute := 0
if matches[3] != "" {
minute, err = strconv.Atoi(matches[3])
if err != nil {
return time.Time{}, err
}
}
meridian := matches[4]
if meridian == "pm" && hour != 12 {
hour += 12
}
if meridian == "am" && hour == 12 {
hour = 0
}
builtTime = time.Date(builtTime.Year(), builtTime.Month(), builtTime.Day(), hour, minute, 0, 0, builtTime.Location())
}
if builtTime.IsZero() {
return time.Time{}, ErrTimeFormat
}
return builtTime, nil
}