-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
naturaldate.go
117 lines (98 loc) · 2.48 KB
/
naturaldate.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
//go:generate peg -inline -switch grammar.peg
// Package naturaldate provides natural date time parsing.
package naturaldate
import (
"strings"
"time"
)
// day duration.
var day = time.Hour * 24
// week duration.
var week = time.Hour * 24 * 7
// Direction is the direction used for ambiguous expressions.
type Direction int
// Directions available.
const (
Past Direction = iota
Future
)
// Option function.
type Option func(*parser)
// WithDirection sets the direction used for ambiguous expressions. By default
// the Past direction is used, so "sunday" will be the previous Sunday, rather
// than the next Sunday.
func WithDirection(d Direction) Option {
return func(p *parser) {
switch d {
case Past:
p.direction = -1
case Future:
p.direction = 1
default:
panic("unhandled direction")
}
}
}
// Parse query string.
func Parse(s string, ref time.Time, options ...Option) (time.Time, error) {
p := &parser{
Buffer: strings.ToLower(s),
direction: -1,
t: ref,
}
for _, o := range options {
o(p)
}
p.Init()
if err := p.Parse(); err != nil {
return time.Time{}, err
}
p.Execute()
// p.PrintSyntaxTree()
return p.t, nil
}
// withDirection returns duration with direction.
func (p *parser) withDirection(d time.Duration) time.Duration {
return d * time.Duration(p.direction)
}
// prevWeekday returns the previous week day relative to time t.
func prevWeekday(t time.Time, day time.Weekday) time.Time {
d := t.Weekday() - day
if d <= 0 {
d += 7
}
return t.Add(-time.Hour * 24 * time.Duration(d))
}
// nextWeekday returns the next week day relative to time t.
func nextWeekday(t time.Time, day time.Weekday) time.Time {
d := day - t.Weekday()
if d <= 0 {
d += 7
}
return t.Add(time.Hour * 24 * time.Duration(d))
}
// nextMonth returns the next month relative to time t.
func nextMonth(t time.Time, month time.Month) time.Time {
y := t.Year()
if month-t.Month() <= 0 {
y++
}
_, _, day := t.Date()
hour, min, sec := t.Clock()
return time.Date(y, month, day, hour, min, sec, 0, t.Location())
}
// prevMonth returns the next month relative to time t.
func prevMonth(t time.Time, month time.Month) time.Time {
y := t.Year()
if t.Month()-month <= 0 {
y--
}
_, _, day := t.Date()
hour, min, sec := t.Clock()
return time.Date(y, month, day, hour, min, sec, 0, t.Location())
}
// truncateDay returns a date truncated to the day.
func truncateDay(t time.Time) time.Time {
y, m, d := t.Date()
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
}