343 lines
7.3 KiB
Plaintext
343 lines
7.3 KiB
Plaintext
package naturaldate
|
|
|
|
import "time"
|
|
|
|
type parser Peg {
|
|
t time.Time
|
|
number int
|
|
month time.Month
|
|
weekday time.Weekday
|
|
direction int
|
|
}
|
|
|
|
Query
|
|
<- _ Expr+ EOF
|
|
|
|
Expr
|
|
<- NOW
|
|
/ RelativeMinutes
|
|
/ RelativeHours
|
|
/ RelativeDays
|
|
/ RelativeWeeks
|
|
/ RelativeWeekdays
|
|
/ RelativeMonth
|
|
/ RelativeYear
|
|
/ Date
|
|
/ Time
|
|
/ Word
|
|
|
|
RelativeMinutes
|
|
<- Number MINUTES AGO
|
|
{
|
|
p.t = p.t.Add(-time.Minute * time.Duration(p.number))
|
|
}
|
|
/ (Number MINUTES FROM_NOW / In Number? MINUTES FROM_NOW?)
|
|
{
|
|
p.t = p.t.Add(time.Minute * time.Duration(p.number))
|
|
}
|
|
/ Last Number? MINUTES
|
|
{
|
|
p.t = p.t.Add(-time.Minute * time.Duration(p.number))
|
|
}
|
|
/ Next Number? MINUTES
|
|
{
|
|
p.t = p.t.Add(time.Minute * time.Duration(p.number))
|
|
}
|
|
/ Number MINUTES
|
|
{
|
|
p.t = p.t.Add(p.withDirection(time.Minute) * time.Duration(p.number))
|
|
}
|
|
|
|
RelativeHours
|
|
<- Number HOURS AGO
|
|
{
|
|
p.t = p.t.Add(-time.Hour * time.Duration(p.number))
|
|
}
|
|
/ (Number HOURS FROM_NOW / In Number? HOURS FROM_NOW?)
|
|
{
|
|
p.t = p.t.Add(time.Hour * time.Duration(p.number))
|
|
}
|
|
/ Last Number? HOURS
|
|
{
|
|
p.t = p.t.Add(-time.Hour * time.Duration(p.number))
|
|
}
|
|
/ Next Number? HOURS
|
|
{
|
|
p.t = p.t.Add(time.Hour * time.Duration(p.number))
|
|
}
|
|
/ Number HOURS
|
|
{
|
|
p.t = p.t.Add(p.withDirection(time.Hour) * time.Duration(p.number))
|
|
}
|
|
|
|
RelativeDays
|
|
<- Number DAYS AGO
|
|
{
|
|
p.t = truncateDay(p.t.Add(-day * time.Duration(p.number)))
|
|
}
|
|
/ (Number DAYS FROM_NOW / In Number? DAYS FROM_NOW?)
|
|
{
|
|
p.t = p.t.Add(day * time.Duration(p.number))
|
|
}
|
|
/ Last Number? DAYS
|
|
{
|
|
p.t = truncateDay(p.t.Add(-day * time.Duration(p.number)))
|
|
}
|
|
/ Next Number? DAYS
|
|
{
|
|
p.t = truncateDay(p.t.Add(day * time.Duration(p.number)))
|
|
}
|
|
/ Number DAYS
|
|
{
|
|
p.t = truncateDay(p.t.Add(p.withDirection(day) * time.Duration(p.number)))
|
|
}
|
|
|
|
RelativeWeeks
|
|
<- Number WEEKS AGO
|
|
{
|
|
p.t = truncateDay(p.t.Add(-week * time.Duration(p.number)))
|
|
}
|
|
/ (Number WEEKS FROM_NOW / In Number? WEEKS FROM_NOW?)
|
|
{
|
|
p.t = p.t.Add(week * time.Duration(p.number))
|
|
}
|
|
/ Last Number? WEEKS
|
|
{
|
|
p.t = truncateDay(p.t.Add(-week * time.Duration(p.number)))
|
|
}
|
|
/ Next Number? WEEKS
|
|
{
|
|
p.t = truncateDay(p.t.Add(week * time.Duration(p.number)))
|
|
}
|
|
/ Number WEEKS
|
|
{
|
|
p.t = truncateDay(p.t.Add(p.withDirection(week) * time.Duration(p.number)))
|
|
}
|
|
|
|
RelativeMonth
|
|
<- Number MONTHS AGO
|
|
{
|
|
p.t = p.t.AddDate(0, -p.number, 0)
|
|
}
|
|
/ (Number MONTHS FROM_NOW / In Number? MONTHS FROM_NOW?)
|
|
{
|
|
p.t = p.t.AddDate(0, p.number, 0)
|
|
}
|
|
/ Last Number? MONTHS
|
|
{
|
|
p.t = p.t.AddDate(0, -p.number, 0)
|
|
}
|
|
/ Next Number? MONTHS
|
|
{
|
|
p.t = p.t.AddDate(0, p.number, 0)
|
|
}
|
|
/ LAST Month
|
|
{
|
|
p.t = prevMonth(p.t, p.month)
|
|
}
|
|
/ NEXT Month
|
|
{
|
|
p.t = nextMonth(p.t, p.month)
|
|
}
|
|
/ Month
|
|
{
|
|
if p.direction < 0 {
|
|
p.t = prevMonth(p.t, p.month)
|
|
} else {
|
|
p.t = nextMonth(p.t, p.month)
|
|
}
|
|
}
|
|
|
|
RelativeYear
|
|
<- Number YEARS AGO
|
|
{
|
|
p.t = p.t.AddDate(-p.number, 0, 0)
|
|
}
|
|
/ (Number YEARS FROM_NOW / In Number? YEARS FROM_NOW?)
|
|
{
|
|
p.t = p.t.AddDate(p.number, 0, 0)
|
|
}
|
|
/ Last Number? YEARS
|
|
{
|
|
p.t = p.t.AddDate(-p.number, 0, 0)
|
|
}
|
|
/ Next Number? YEARS
|
|
{
|
|
p.t = p.t.AddDate(p.number, 0, 0)
|
|
}
|
|
/ LAST YEARS
|
|
{
|
|
p.t = time.Date(p.t.Year() - 1, 1, 1, 0, 0, 0, 0, p.t.Location())
|
|
}
|
|
/ NEXT YEARS
|
|
{
|
|
p.t = time.Date(p.t.Year() + 1, 1, 1, 0, 0, 0, 0, p.t.Location())
|
|
}
|
|
|
|
|
|
RelativeWeekdays
|
|
<- TODAY
|
|
{
|
|
p.t = truncateDay(p.t)
|
|
}
|
|
/ YESTERDAY
|
|
{
|
|
p.t = truncateDay(p.t.Add(-day))
|
|
}
|
|
/ TOMORROW
|
|
{
|
|
p.t = truncateDay(p.t.Add(+day))
|
|
}
|
|
/ LAST Weekday
|
|
{
|
|
p.t = truncateDay(prevWeekday(p.t, p.weekday))
|
|
}
|
|
/ NEXT Weekday
|
|
{
|
|
p.t = truncateDay(nextWeekday(p.t, p.weekday))
|
|
}
|
|
/ Weekday
|
|
{
|
|
if p.direction < 0 {
|
|
p.t = truncateDay(prevWeekday(p.t, p.weekday))
|
|
} else {
|
|
p.t = truncateDay(nextWeekday(p.t, p.weekday))
|
|
}
|
|
}
|
|
|
|
Date
|
|
<- (Number Ordinal / Last Number? Number)
|
|
{
|
|
t := p.t
|
|
year, month, _ := t.Date()
|
|
hour, min, sec := t.Clock()
|
|
p.t = time.Date(year, month, p.number, hour, min, sec, 0, t.Location())
|
|
}
|
|
|
|
Time
|
|
<- Clock12Hour
|
|
/ Clock24Hour
|
|
|
|
Clock12Hour
|
|
<- Number
|
|
{
|
|
year, month, day := p.t.Date()
|
|
p.t = time.Date(year, month, day, p.number, 0, 0, 0, p.t.Location())
|
|
}
|
|
(Minutes Seconds?)?
|
|
AM
|
|
/ Number
|
|
{
|
|
year, month, day := p.t.Date()
|
|
p.t = time.Date(year, month, day, p.number + 12, 0, 0, 0, p.t.Location())
|
|
}
|
|
(Minutes Seconds?)?
|
|
PM
|
|
|
|
Clock24Hour
|
|
<- Number
|
|
{
|
|
year, month, day := p.t.Date()
|
|
p.t = time.Date(year, month, day, p.number, 0, 0, 0, p.t.Location())
|
|
}
|
|
(Minutes Seconds?)?
|
|
|
|
Minutes
|
|
<- ':' Number
|
|
{
|
|
t := p.t
|
|
year, month, day := t.Date()
|
|
hour, _, _ := t.Clock()
|
|
p.t = time.Date(year, month, day, hour, p.number, 0, 0, t.Location())
|
|
}
|
|
|
|
Seconds
|
|
<- ':' Number
|
|
{
|
|
t := p.t
|
|
year, month, day := t.Date()
|
|
hour, min, _ := t.Clock()
|
|
p.t = time.Date(year, month, day, hour, min, p.number, 0, t.Location())
|
|
}
|
|
|
|
Number
|
|
<- < [0-9]+ > _ { n, _ := strconv.Atoi(text); p.number = n }
|
|
/ 'one' _ { p.number = 1 }
|
|
/ 'two' _ { p.number = 2 }
|
|
/ 'three' _ { p.number = 3 }
|
|
/ 'four' _ { p.number = 4 }
|
|
/ 'five' _ { p.number = 5 }
|
|
/ 'six' _ { p.number = 6 }
|
|
/ 'seven' _ { p.number = 7 }
|
|
/ 'eight' _ { p.number = 8 }
|
|
/ 'nine' _ { p.number = 9 }
|
|
/ 'ten' _ { p.number = 10 }
|
|
|
|
Weekday
|
|
<- 'sunday' _ { p.weekday = time.Sunday }
|
|
/ 'monday' _ { p.weekday = time.Monday }
|
|
/ 'tuesday' _ { p.weekday = time.Tuesday }
|
|
/ 'wednesday' _ { p.weekday = time.Wednesday }
|
|
/ 'thursday' _ { p.weekday = time.Thursday }
|
|
/ 'friday' _ { p.weekday = time.Friday }
|
|
/ 'saturday' _ { p.weekday = time.Saturday }
|
|
|
|
Month
|
|
<- 'january' _ { p.month = time.January }
|
|
/ 'february' _ { p.month = time.February }
|
|
/ 'march' _ { p.month = time.March }
|
|
/ 'april' _ { p.month = time.April }
|
|
/ 'may' _ { p.month = time.May }
|
|
/ 'june' _ { p.month = time.June }
|
|
/ 'july' _ { p.month = time.July }
|
|
/ 'august' _ { p.month = time.August }
|
|
/ 'september' _ { p.month = time.September }
|
|
/ 'october' _ { p.month = time.October }
|
|
/ 'november' _ { p.month = time.November }
|
|
/ 'december' _ { p.month = time.December }
|
|
|
|
In
|
|
<- IN { p.number = 1}
|
|
|
|
Last
|
|
<- LAST { p.number = 1 }
|
|
|
|
Next
|
|
<- NEXT { p.number = 1 }
|
|
|
|
Ordinal
|
|
<- ('st' / 'nd' / 'rd' / 'th') _
|
|
|
|
Word
|
|
<- [a-z]+ _
|
|
|
|
YEARS <- 'year' 's'? _
|
|
MONTHS <- 'month' 's'? _
|
|
WEEKS <- 'week' 's'? _
|
|
DAYS <- 'day' 's'? _
|
|
HOURS <- 'hour' 's'? _
|
|
MINUTES <- 'minute' 's'? _
|
|
YESTERDAY <- 'yesterday' _
|
|
TOMORROW <- 'tomorrow' _
|
|
TODAY <- 'today' _
|
|
AGO <- 'ago' _
|
|
FROM_NOW <- 'from now' _
|
|
NOW <- 'now' _
|
|
AM <- 'am' _
|
|
PM <- 'pm' _
|
|
NEXT <- 'next' _
|
|
IN <- ('in an' / 'in a' / 'in') _
|
|
LAST <- ('last' / 'past' / 'previous') _
|
|
|
|
_
|
|
<- Whitespace*
|
|
|
|
Whitespace
|
|
<- ' ' / '\t' / EOL
|
|
|
|
EOL
|
|
<- '\r\n' / '\n' / '\r'
|
|
|
|
EOF
|
|
<- !.
|