Skip to main content

fuzzydate/
ast.rs

1use chrono::{
2    DateTime as ChronoDateTime, Datelike, Duration as ChronoDuration, NaiveDate as ChronoDate,
3    NaiveDateTime, NaiveTime as ChronoTime, TimeZone, Weekday as ChronoWeekday,
4};
5
6use crate::lexer::Lexeme;
7
8#[derive(Debug, Eq, PartialEq)]
9#[allow(clippy::enum_variant_names)]
10/// Root of the Abstract Syntax Tree, represents a fully parsed DateTime
11pub enum DateTime {
12    /// Standard date and time
13    DateTime(DateExpr, Time),
14    /// Time before date
15    TimeDate(Time, DateExpr),
16    /// Duration after a datetime
17    After(Duration, Box<DateTime>),
18    /// Duration before a datetime
19    Before(Duration, Box<DateTime>),
20    /// The current datetime
21    Now,
22}
23
24impl DateTime {
25    /// Parse a datetime from a slice of lexemes
26    pub fn parse(l: &[Lexeme]) -> Option<(Self, usize)> {
27        let mut tokens = 0;
28
29        if l.get(tokens) == Some(&Lexeme::Now) {
30            tokens += 1;
31            return Some((Self::Now, tokens));
32        }
33
34        if let Some((date_expr, t)) = DateExpr::parse(&l[tokens..]) {
35            tokens += t;
36
37            if l.get(tokens) == Some(&Lexeme::Comma) || l.get(tokens) == Some(&Lexeme::At) {
38                tokens += 1;
39            }
40
41            if let Some((time, t)) = Time::parse(&l[tokens..]) {
42                tokens += t;
43                return Some((Self::DateTime(date_expr, time), tokens));
44            }
45
46            return Some((Self::DateTime(date_expr, Time::Empty), tokens));
47        }
48
49        // Date also accepts a leading duration and should take precedence. For example,
50        // "3 days ago" is a date specified by duration, not a duration modifying a datetime
51        if let Some((dur, t)) = Duration::parse(&l[tokens..]) {
52            tokens += t;
53
54            if Some(&Lexeme::After) == l.get(tokens) {
55                tokens += 1;
56
57                if let Some((datetime, t)) = DateTime::parse(&l[tokens..]) {
58                    tokens += t;
59                    return Some((Self::After(dur, Box::new(datetime)), tokens));
60                }
61
62                return None;
63            }
64
65            if Some(&Lexeme::From) == l.get(tokens) {
66                tokens += 1;
67
68                if let Some((datetime, t)) = DateTime::parse(&l[tokens..]) {
69                    tokens += t;
70                    return Some((Self::After(dur, Box::new(datetime)), tokens));
71                }
72
73                return None;
74            }
75
76            if Some(&Lexeme::Before) == l.get(tokens) {
77                tokens += 1;
78
79                if let Some((datetime, t)) = DateTime::parse(&l[tokens..]) {
80                    tokens += t;
81                    return Some((Self::Before(dur, Box::new(datetime)), tokens));
82                }
83
84                return None;
85            }
86
87            if Some(&Lexeme::Ago) == l.get(tokens) {
88                tokens += 1;
89                return Some((Self::Before(dur, Box::new(Self::Now)), tokens));
90            }
91
92            return None;
93        }
94
95        // time binds really eagerly. A bare number is a valid time, but can also be the start of a
96        // date or duration expression, so we need to check time last
97        if let Some((time, t)) = Time::parse(&l[tokens..]) {
98            tokens += t;
99
100            if l.get(tokens) == Some(&Lexeme::Comma) || l.get(tokens) == Some(&Lexeme::On) {
101                tokens += 1;
102            }
103
104            if let Some((date_expr, t)) = DateExpr::parse(&l[tokens..]) {
105                tokens += t;
106                return Some((Self::TimeDate(time, date_expr), tokens));
107            }
108
109            return Some((Self::TimeDate(time, DateExpr::Empty), tokens));
110        }
111
112        None
113    }
114
115    /// Convert a parsed DateTime to chrono's DateTime
116    pub fn to_chrono<Tz: TimeZone>(
117        &self,
118        now: ChronoDateTime<Tz>,
119    ) -> Result<ChronoDateTime<Tz>, crate::Error> {
120        Ok(match self {
121            DateTime::Now => now,
122            DateTime::DateTime(date, time) => {
123                let date = date.to_chrono(now.to_owned())?;
124                let time = time.to_chrono(now.to_owned())?;
125
126                NaiveDateTime::new(date, time)
127                    .and_local_timezone(now.timezone())
128                    .earliest()
129                    .ok_or(crate::Error::ParseError)?
130            }
131            DateTime::TimeDate(time, date) => {
132                let date = date.to_chrono(now.to_owned())?;
133                let time = time.to_chrono(now.to_owned())?;
134
135                NaiveDateTime::new(date, time)
136                    .and_local_timezone(now.timezone())
137                    .earliest()
138                    .ok_or(crate::Error::ParseError)?
139            }
140            DateTime::After(dur, date) => {
141                let date = date.to_chrono(now)?;
142                dur.after(date)
143            }
144            DateTime::Before(dur, date) => {
145                let date = date.to_chrono(now)?;
146                dur.before(date)
147            }
148        })
149    }
150}
151
152#[derive(Debug, Eq, PartialEq)]
153/// A Parsed Date Expression
154pub enum DateExpr {
155    Date(Date),
156    // Only supports years
157    DateRelative(Date, RelativeSpecifier, Unit),
158    // January 24th in 3 years
159    DateExpressionAfter(Date, Duration),
160    DateExpressionBefore(Date, Duration),
161    UnitRelative(RelativeSpecifier, Unit),
162    RelativeWeekday(RelativeSpecifier, Weekday),
163    WeekdayRelative(Weekday, RelativeSpecifier, Unit),
164    // Tuesday in two weeks
165    WeekdayExpressionAfter(Weekday, Duration),
166    WeekdayExpressionBefore(Weekday, Duration),
167    Before(Duration, Date),
168    After(Duration, Date),
169    // the next instance of this week day, might be in the current or next week
170    Weekday(Weekday),
171    Empty,
172}
173
174impl DateExpr {
175    fn parse(l: &[Lexeme]) -> Option<(Self, usize)> {
176        let mut tokens = 0;
177
178        if let Some((date, t)) = Date::parse(&l[tokens..]) {
179            tokens += t;
180            // stash the tokens here, if we fail to parse a more complex expression
181            // we'll return the date and continue parsing, but we might have
182            // a dirty token state by the time we get to return
183            let date_tokens = tokens;
184
185            if let Some((spec, t)) = RelativeSpecifier::parse(&l[tokens..]) {
186                tokens += t;
187                if let Some((unit, t)) = Unit::parse(&l[tokens..]) {
188                    tokens += t;
189                    return Some((Self::DateRelative(date, spec, unit), tokens));
190                }
191            } else if let Some((duration, t)) = Duration::parse(&l[tokens..]) {
192                tokens += t;
193
194                if l.get(tokens) == Some(&Lexeme::Ago) && !duration.is_sub_daily() {
195                    tokens += 1;
196                    return Some((Self::DateExpressionBefore(date, duration), tokens));
197                }
198            } else if let Some(Lexeme::In) = l[tokens..].first() {
199                tokens += 1;
200                if let Some((duration, t)) = Duration::parse(&l[tokens..]) {
201                    if !duration.is_sub_daily() {
202                        tokens += t;
203                        return Some((Self::DateExpressionAfter(date, duration), tokens));
204                    }
205                }
206            }
207            return Some((Self::Date(date), date_tokens));
208        }
209
210        tokens = 0;
211        if let Some((duration, t)) = Duration::parse(l) {
212            tokens += t;
213
214            if duration.is_sub_daily() {
215                return None;
216            }
217
218            if l.get(tokens) == Some(&Lexeme::Ago) {
219                tokens += 1;
220                return Some((Self::Before(duration, Date::Empty), tokens));
221            }
222
223            if l.get(tokens) == Some(&Lexeme::After) {
224                tokens += 1;
225                if let Some((date, t)) = Date::parse(&l[tokens..]) {
226                    tokens += t;
227
228                    return Some((Self::After(duration, date), tokens));
229                }
230
231                return None;
232            }
233
234            if l.get(tokens) == Some(&Lexeme::From) {
235                tokens += 1;
236                if let Some((date, t)) = Date::parse(&l[tokens..]) {
237                    tokens += t;
238
239                    return Some((Self::After(duration, date), tokens));
240                }
241
242                return None;
243            }
244
245            return None;
246        }
247
248        tokens = 0;
249        if let Some((weekday, t)) = Weekday::parse(&l[tokens..]) {
250            tokens += t;
251
252            if let Some((relspec, t)) = RelativeSpecifier::parse(&l[tokens..]) {
253                tokens += t;
254                if let Some((unit, t)) = Unit::parse(&l[tokens..]) {
255                    tokens += t;
256                    return Some((Self::WeekdayRelative(weekday, relspec, unit), tokens));
257                }
258            } else if let Some((duration, t)) = Duration::parse(&l[tokens..]) {
259                tokens += t;
260
261                if l.get(tokens) == Some(&Lexeme::Ago) && !duration.is_sub_daily() {
262                    tokens += 1;
263                    return Some((Self::WeekdayExpressionBefore(weekday, duration), tokens));
264                }
265            } else if let Some(Lexeme::In) = l[tokens..].first() {
266                tokens += 1;
267                if let Some((duration, t)) = Duration::parse(&l[tokens..]) {
268                    if !duration.is_sub_daily() {
269                        tokens += t;
270                        return Some((Self::WeekdayExpressionBefore(weekday, duration), tokens));
271                    }
272                }
273            }
274
275            return Some((Self::Weekday(weekday), tokens));
276        }
277
278        tokens = 0;
279        if let Some((relspec, t)) = RelativeSpecifier::parse(&l[tokens..]) {
280            tokens += t;
281
282            if let Some((weekday, t)) = Weekday::parse(&l[tokens..]) {
283                tokens += t;
284                return Some((Self::RelativeWeekday(relspec, weekday), tokens));
285            }
286
287            if let Some((unit, t)) = Unit::parse(&l[tokens..]) {
288                tokens += t;
289                return Some((Self::UnitRelative(relspec, unit), tokens));
290            }
291
292            return None;
293        }
294
295        None
296    }
297
298    fn to_chrono<Tz: TimeZone>(&self, now: ChronoDateTime<Tz>) -> Result<ChronoDate, crate::Error> {
299        Ok(match self {
300            Self::Date(date) => return date.to_chrono(now),
301            Self::DateRelative(date, relspec, unit) => {
302                if !matches!(unit, Unit::Year) {
303                    return Err(crate::Error::ParseError);
304                }
305
306                let parsed_date = match date {
307                    Date::MonthNumDayYear(_, _, _)
308                    | Date::MonthDayYear(_, _, _)
309                    | Date::YearMonthNumDay(_, _, _)
310                    | Date::DayMonthYear(_, _, _)
311                    | Date::Today
312                    | Date::Tomorrow
313                    | Date::Yesterday => {
314                        return Err(crate::Error::ParseError);
315                    }
316                    Date::MonthNumDay(_, _) => date.to_chrono(now)?,
317                    Date::MonthDay(_, _) => date.to_chrono(now)?,
318                    Date::Empty => now.date_naive(),
319                };
320
321                match relspec {
322                    RelativeSpecifier::This => parsed_date,
323                    RelativeSpecifier::Next => {
324                        Duration::Specific(1, *unit).after_date(parsed_date)?
325                    }
326                    RelativeSpecifier::Last => {
327                        Duration::Specific(1, *unit).before_date(parsed_date)?
328                    }
329                }
330            }
331            Self::WeekdayExpressionAfter(weekday, duration) => {
332                let day = weekday.to_chrono();
333                let mut today = duration.after(now).date_naive();
334                while today.weekday() != day {
335                    today += ChronoDuration::days(1);
336                }
337
338                today
339            }
340            Self::WeekdayExpressionBefore(weekday, duration) => {
341                let day = weekday.to_chrono();
342                let mut today = duration.before(now).date_naive();
343                while today.weekday() != day {
344                    today -= ChronoDuration::days(1);
345                }
346
347                today
348            }
349            Self::DateExpressionAfter(date, duration) => {
350                duration.after_date(date.to_chrono(now)?)?
351            }
352            Self::DateExpressionBefore(date, duration) => {
353                duration.before_date(date.to_chrono(now)?)?
354            }
355            Self::Before(dur, date) => dur.before_date(date.to_chrono(now)?)?,
356            Self::After(dur, date) => dur.after_date(date.to_chrono(now)?)?,
357            Self::UnitRelative(spec, unit) => {
358                match spec {
359                    RelativeSpecifier::Next => {
360                        Duration::Specific(1, unit.to_owned()).after_date(now.date_naive())?
361                    }
362                    RelativeSpecifier::Last => {
363                        Duration::Specific(1, unit.to_owned()).before_date(now.date_naive())?
364                    }
365                    RelativeSpecifier::This => {
366                        // This would be nonsense as far as I can tell. An example would
367                        // be "2pm this month"
368                        return Err(crate::Error::ParseError);
369                    }
370                }
371            }
372            Self::RelativeWeekday(spec, day) => {
373                let day = day.to_chrono();
374                let mut today = now.date_naive();
375                let this_week = today.iso_week();
376
377                match spec {
378                    // iterate to the beginning or end of the correct week, then iterate through
379                    // the week to the correct day
380                    RelativeSpecifier::Next => {
381                        while today.iso_week() == this_week {
382                            today += ChronoDuration::days(1);
383                        }
384
385                        while today.weekday() != day {
386                            today += ChronoDuration::days(1);
387                        }
388                    }
389                    RelativeSpecifier::Last => {
390                        while today.iso_week() == this_week {
391                            today -= ChronoDuration::days(1);
392                        }
393                        while today.weekday() != day {
394                            today -= ChronoDuration::days(1);
395                        }
396                    }
397                    RelativeSpecifier::This => {
398                        while today.iso_week() == this_week {
399                            today -= ChronoDuration::days(1);
400                        }
401                        today += ChronoDuration::days(1);
402
403                        while today.weekday() != day {
404                            today += ChronoDuration::days(1);
405                        }
406                    }
407                }
408
409                today
410            }
411            Self::WeekdayRelative(day, relspec, unit) => {
412                if !matches!(unit, Unit::Week) {
413                    return Err(crate::Error::ParseError);
414                }
415
416                let day = day.to_chrono();
417                let mut today = now.date_naive();
418                let this_week = today.iso_week();
419
420                match relspec {
421                    // iterate to the beginning or end of the correct week, then iterate through
422                    // the week to the correct day
423                    RelativeSpecifier::Next => {
424                        while today.iso_week() == this_week {
425                            today += ChronoDuration::days(1);
426                        }
427
428                        while today.weekday() != day {
429                            today += ChronoDuration::days(1);
430                        }
431                    }
432                    RelativeSpecifier::Last => {
433                        while today.iso_week() == this_week {
434                            today -= ChronoDuration::days(1);
435                        }
436                        while today.weekday() != day {
437                            today -= ChronoDuration::days(1);
438                        }
439                    }
440                    RelativeSpecifier::This => {
441                        while today.iso_week() == this_week {
442                            today -= ChronoDuration::days(1);
443                        }
444                        today += ChronoDuration::days(1);
445
446                        while today.weekday() != day {
447                            today += ChronoDuration::days(1);
448                        }
449                    }
450                }
451
452                today
453            }
454            Self::Weekday(day) => {
455                let day = day.to_chrono();
456                let mut today = now.date_naive();
457
458                while today.weekday() != day {
459                    today += ChronoDuration::days(1);
460                }
461
462                today
463            }
464
465            Self::Empty => now.date_naive(),
466        })
467    }
468}
469
470#[derive(Debug, Eq, PartialEq)]
471/// A Parsed Date
472pub enum Date {
473    YearMonthNumDay(u32, u32, u32),
474    MonthNumDayYear(u32, u32, u32),
475    DayMonthYear(u32, Month, u32),
476    MonthDayYear(Month, u32, u32),
477    MonthNumDay(u32, u32),
478    MonthDay(Month, u32),
479    Today,
480    Tomorrow,
481    Yesterday,
482    Empty,
483}
484
485impl Date {
486    fn parse(l: &[Lexeme]) -> Option<(Self, usize)> {
487        let mut tokens = 0;
488
489        if let Some(&Lexeme::Today) = l.get(tokens) {
490            tokens += 1;
491            return Some((Self::Today, tokens));
492        }
493
494        tokens = 0;
495        if let Some(&Lexeme::Tomorrow) = l.get(tokens) {
496            tokens += 1;
497            return Some((Self::Tomorrow, tokens));
498        }
499
500        tokens = 0;
501        if let Some(&Lexeme::Yesterday) = l.get(tokens) {
502            tokens += 1;
503            return Some((Self::Yesterday, tokens));
504        }
505
506        tokens = 0;
507        if let Some((day, t)) = Num::parse(&l[tokens..]) {
508            tokens += t;
509            if let Some((month, t)) = Month::parse(&l[tokens..]) {
510                tokens += t;
511                if let Some((year, t)) = Num::parse(&l[tokens..]) {
512                    tokens += t;
513                    return Some((Self::DayMonthYear(day, month, year), tokens));
514                }
515            }
516        }
517
518        tokens = 0;
519        if let Some((month, t)) = Month::parse(&l[tokens..]) {
520            tokens += t;
521
522            let (num, t) = Num::parse(&l[tokens..])?;
523            tokens += t;
524
525            if let Some((year, t)) = Num::parse(&l[tokens..]) {
526                tokens += t;
527                return Some((Self::MonthDayYear(month, num, year), tokens));
528            }
529
530            return Some((Self::MonthDay(month, num), tokens));
531        }
532
533        tokens = 0;
534        if let Some((num1, t)) = Num::parse(&l[tokens..]) {
535            tokens += t;
536            if let Some(delim) = l.get(tokens) {
537                if delim == &Lexeme::Slash || delim == &Lexeme::Dash || delim == &Lexeme::Dot {
538                    // Consume slash or dash
539                    tokens += 1;
540
541                    if let Some((num2, t)) = Num::parse(&l[tokens..]) {
542                        tokens += t;
543                        if l.get(tokens)? == delim {
544                            // Consume slash or dash
545                            tokens += 1;
546
547                            let (num3, t) = Num::parse(&l[tokens..])?;
548                            tokens += t;
549
550                            if num1 > 1000 {
551                                return Some((Self::YearMonthNumDay(num1, num2, num3), tokens));
552                            }
553
554                            // If delim is dot use DMY, otherwise MDY
555                            if delim == &Lexeme::Dot {
556                                return Some((Self::MonthNumDayYear(num2, num1, num3), tokens));
557                            } else {
558                                return Some((Self::MonthNumDayYear(num1, num2, num3), tokens));
559                            }
560                        } else {
561                            // If delim is dot use DMY, otherwise MDY
562                            if delim == &Lexeme::Dot {
563                                return Some((Self::MonthNumDay(num2, num1), tokens));
564                            } else {
565                                return Some((Self::MonthNumDay(num1, num2), tokens));
566                            }
567                        }
568                    }
569                }
570            }
571        }
572
573        None
574    }
575
576    fn to_chrono<Tz: TimeZone>(&self, now: ChronoDateTime<Tz>) -> Result<ChronoDate, crate::Error> {
577        let today = now.date_naive();
578        Ok(match self {
579            Self::Today => today,
580            Self::Yesterday => today - ChronoDuration::days(1),
581            Self::Tomorrow => today + ChronoDuration::days(1),
582            Self::MonthNumDay(month, day) => ChronoDate::from_ymd_opt(today.year(), *month, *day)
583                .ok_or(crate::Error::InvalidDate(format!(
584                "Invalid month-day: {month}-{day}"
585            )))?,
586            Self::MonthNumDayYear(month, day, year) | Self::YearMonthNumDay(year, month, day) => {
587                let curr = today.year() as u32;
588                let year = if *year < 100 {
589                    if curr + 10 < 2000 + *year {
590                        1900 + *year
591                    } else {
592                        2000 + *year
593                    }
594                } else {
595                    *year
596                };
597
598                ChronoDate::from_ymd_opt(year as i32, *month, *day).ok_or(
599                    crate::Error::InvalidDate(format!(
600                        "Invalid year-month-day: {year}-{month}-{day}"
601                    )),
602                )?
603            }
604            Self::MonthDay(month, day) => {
605                let month = *month as u32;
606                ChronoDate::from_ymd_opt(today.year(), month, *day).ok_or(
607                    crate::Error::InvalidDate(format!("Invalid month-day: {month}-{day}")),
608                )?
609            }
610            Self::MonthDayYear(month, day, year) | Self::DayMonthYear(day, month, year) => {
611                ChronoDate::from_ymd_opt(*year as i32, *month as u32, *day).ok_or(
612                    crate::Error::InvalidDate(format!(
613                        "Invalid year-month-day: {}-{}-{}",
614                        *year, *month as u32, *day
615                    )),
616                )?
617            }
618            Self::Empty => now.date_naive(),
619        })
620    }
621}
622
623#[derive(Debug, Eq, PartialEq)]
624pub enum RelativeSpecifier {
625    This,
626    Next,
627    Last,
628}
629
630impl RelativeSpecifier {
631    fn parse(l: &[Lexeme]) -> Option<(Self, usize)> {
632        let res = match l.first() {
633            Some(Lexeme::This) => Some(Self::This),
634            Some(Lexeme::Next) => Some(Self::Next),
635            Some(Lexeme::Last) => Some(Self::Last),
636            _ => None,
637        };
638
639        res.map(|e| (e, 1))
640    }
641}
642
643#[derive(Debug, Eq, PartialEq)]
644pub enum Weekday {
645    Monday,
646    Tuesday,
647    Wednesday,
648    Thursday,
649    Friday,
650    Saturday,
651    Sunday,
652}
653
654impl Weekday {
655    fn parse(l: &[Lexeme]) -> Option<(Self, usize)> {
656        let res = match l.first() {
657            Some(Lexeme::Sunday) => Some(Self::Sunday),
658            Some(Lexeme::Monday) => Some(Self::Monday),
659            Some(Lexeme::Tuesday) => Some(Self::Tuesday),
660            Some(Lexeme::Wednesday) => Some(Self::Wednesday),
661            Some(Lexeme::Thursday) => Some(Self::Thursday),
662            Some(Lexeme::Friday) => Some(Self::Friday),
663            Some(Lexeme::Saturday) => Some(Self::Saturday),
664            _ => None,
665        };
666
667        res.map(|e| (e, 1))
668    }
669
670    fn to_chrono(&self) -> ChronoWeekday {
671        match *self {
672            Weekday::Monday => ChronoWeekday::Mon,
673            Weekday::Tuesday => ChronoWeekday::Tue,
674            Weekday::Wednesday => ChronoWeekday::Wed,
675            Weekday::Thursday => ChronoWeekday::Thu,
676            Weekday::Friday => ChronoWeekday::Fri,
677            Weekday::Saturday => ChronoWeekday::Sat,
678            Weekday::Sunday => ChronoWeekday::Sun,
679        }
680    }
681}
682
683#[derive(Debug, Eq, PartialEq, Clone, Copy)]
684pub enum Month {
685    January = 1,
686    February = 2,
687    March = 3,
688    April = 4,
689    May = 5,
690    June = 6,
691    July = 7,
692    August = 8,
693    September = 9,
694    October = 10,
695    November = 11,
696    December = 12,
697}
698
699impl Month {
700    fn parse(l: &[Lexeme]) -> Option<(Self, usize)> {
701        let res = match l.first() {
702            Some(Lexeme::January) => Some(Self::January),
703            Some(Lexeme::February) => Some(Self::February),
704            Some(Lexeme::March) => Some(Self::March),
705            Some(Lexeme::April) => Some(Self::April),
706            Some(Lexeme::May) => Some(Self::May),
707            Some(Lexeme::June) => Some(Self::June),
708            Some(Lexeme::July) => Some(Self::July),
709            Some(Lexeme::August) => Some(Self::August),
710            Some(Lexeme::September) => Some(Self::September),
711            Some(Lexeme::October) => Some(Self::October),
712            Some(Lexeme::November) => Some(Self::November),
713            Some(Lexeme::December) => Some(Self::December),
714            _ => None,
715        };
716
717        res.map(|e| (e, 1))
718    }
719}
720
721#[derive(Debug, Eq, PartialEq)]
722pub enum Time {
723    HourMin(u32, u32),
724    HourMinAM(u32, u32),
725    HourMinPM(u32, u32),
726    Empty,
727}
728
729impl Time {
730    fn parse(l: &[Lexeme]) -> Option<(Self, usize)> {
731        let mut tokens = 0;
732
733        if let Some(&Lexeme::Midnight) = l.get(tokens) {
734            tokens += 1;
735            return Some((Time::HourMin(0, 0), tokens));
736        }
737
738        if let Some(&Lexeme::Noon) = l.get(tokens) {
739            tokens += 1;
740            return Some((Time::HourMin(12, 0), tokens));
741        }
742
743        if let Some((hour, t)) = Num::parse(&l[tokens..]) {
744            tokens += t;
745            let mut minute = 0;
746            if l.get(tokens) == Some(&Lexeme::Colon) {
747                tokens += 1;
748
749                if let Some((min, t)) = Num::parse(&l[tokens..]) {
750                    tokens += t;
751                    minute = min;
752                }
753            }
754            if let Some(&Lexeme::AM) = l.get(tokens) {
755                tokens += 1;
756                return Some((Time::HourMinAM(hour, minute), tokens));
757            } else if let Some(&Lexeme::PM) = l.get(tokens) {
758                tokens += 1;
759                return Some((Time::HourMinPM(hour, minute), tokens));
760            } else {
761                return Some((Time::HourMin(hour, minute), tokens));
762            }
763        }
764
765        None
766    }
767
768    fn to_chrono<Tz: TimeZone>(&self, now: ChronoDateTime<Tz>) -> Result<ChronoTime, crate::Error> {
769        match *self {
770            Self::Empty => Ok(now.time()),
771            Time::HourMin(hour, min) => ChronoTime::from_hms_opt(hour, min, 0).ok_or(
772                crate::Error::InvalidDate(format!("Invalid time: {hour}:{min}")),
773            ),
774            Time::HourMinAM(hour, min) => ChronoTime::from_hms_opt(hour, min, 0).ok_or(
775                crate::Error::InvalidDate(format!("Invalid time: {hour}:{min} am")),
776            ),
777            Time::HourMinPM(hour, min) => ChronoTime::from_hms_opt(hour + 12, min, 0).ok_or(
778                crate::Error::InvalidDate(format!("Invalid time: {hour}:{min} pm")),
779            ),
780        }
781    }
782}
783
784#[derive(Debug, Eq, PartialEq)]
785pub enum Article {
786    A,
787    An,
788    The,
789}
790
791impl Article {
792    fn parse(l: &[Lexeme]) -> Option<(Self, usize)> {
793        match l.first() {
794            Some(Lexeme::A) => Some((Self::A, 1)),
795            Some(Lexeme::An) => Some((Self::An, 1)),
796            Some(Lexeme::The) => Some((Self::The, 1)),
797            _ => None,
798        }
799    }
800}
801
802#[derive(Debug, Eq, PartialEq)]
803pub enum Duration {
804    Article(Unit),
805    Specific(u32, Unit),
806    Concat(Box<Duration>, Box<Duration>),
807}
808
809impl Duration {
810    fn parse(l: &[Lexeme]) -> Option<(Self, usize)> {
811        let mut tokens = 0;
812        if let Some((d, t)) = Duration::parse_concrete(l) {
813            tokens += t;
814
815            if let Some(Lexeme::And) = l.get(tokens) {
816                tokens += 1;
817
818                if let Some((dur2, t)) = Duration::parse(&l[tokens..]) {
819                    tokens += t;
820
821                    return Some((Duration::Concat(Box::new(d), Box::new(dur2)), tokens));
822                }
823            }
824
825            return Some((d, t));
826        }
827
828        None
829    }
830
831    fn parse_concrete(l: &[Lexeme]) -> Option<(Self, usize)> {
832        let mut tokens = 0;
833
834        if let Some((num, t)) = Num::parse(&l[tokens..]) {
835            tokens += t;
836            if let Some((u, t)) = Unit::parse(&l[tokens..]) {
837                tokens += t;
838                return Some((Self::Specific(num, u), tokens));
839            }
840        }
841
842        tokens = 0;
843        if let Some((_, t)) = Article::parse(l) {
844            tokens += t;
845            if let Some((u, t)) = Unit::parse(&l[tokens..]) {
846                tokens += t;
847                return Some((Self::Article(u), tokens));
848            }
849        }
850
851        None
852    }
853
854    fn unit(&self) -> &Unit {
855        match self {
856            Duration::Article(u) => u,
857            Duration::Specific(_, u) => u,
858            _ => unimplemented!(),
859        }
860    }
861
862    fn num(&self) -> u32 {
863        match *self {
864            Duration::Article(_) => 1,
865            Duration::Specific(num, _) => num,
866            _ => unimplemented!(),
867        }
868    }
869
870    fn convertible(&self) -> bool {
871        if let Duration::Concat(dur1, dur2) = self {
872            return dur1.convertible() && dur2.convertible();
873        }
874
875        let unit = self.unit();
876        unit != &Unit::Month && unit != &Unit::Year
877    }
878
879    fn to_chrono(&self) -> ChronoDuration {
880        if let Duration::Concat(dur1, dur2) = self {
881            return dur1.to_chrono() + dur2.to_chrono();
882        }
883
884        let unit = self.unit();
885        let num = self.num();
886
887        match unit {
888            Unit::Day => ChronoDuration::days(num as i64),
889            Unit::Week => ChronoDuration::weeks(num as i64),
890            Unit::Hour => ChronoDuration::hours(num as i64),
891            Unit::Minute => ChronoDuration::minutes(num as i64),
892            _ => unreachable!(),
893        }
894    }
895
896    fn after<Tz: TimeZone>(&self, date: ChronoDateTime<Tz>) -> ChronoDateTime<Tz> {
897        if let Duration::Concat(dur1, dur2) = self {
898            return dur2.after(dur1.after(date));
899        }
900
901        if self.convertible() {
902            date + self.to_chrono()
903        } else {
904            match self.unit() {
905                Unit::Month => date
906                    .checked_add_months(chrono::Months::new(self.num()))
907                    .expect("Date out of representable date range."),
908                Unit::Year => date.with_year(date.year() + self.num() as i32).unwrap(),
909                _ => unreachable!(),
910            }
911        }
912    }
913
914    fn before<Tz: TimeZone>(&self, date: ChronoDateTime<Tz>) -> ChronoDateTime<Tz> {
915        if let Duration::Concat(dur1, dur2) = self {
916            return dur2.before(dur1.before(date));
917        }
918
919        if self.convertible() {
920            date - self.to_chrono()
921        } else {
922            match self.unit() {
923                Unit::Month => date
924                    .checked_sub_months(chrono::Months::new(self.num()))
925                    .expect("Date out of representable date range."),
926                Unit::Year => date.with_year(date.year() - self.num() as i32).unwrap(),
927                _ => unreachable!(),
928            }
929        }
930    }
931
932    fn after_date(&self, date: ChronoDate) -> Result<ChronoDate, crate::Error> {
933        if self.is_sub_daily() {
934            // TODO: better error
935            return Err(crate::Error::ParseError);
936        }
937
938        if let Duration::Concat(dur1, dur2) = self {
939            return dur2.after_date(dur1.after_date(date)?);
940        }
941
942        if self.convertible() {
943            Ok(date + self.to_chrono())
944        } else {
945            match self.unit() {
946                Unit::Month => date
947                    .checked_add_months(chrono::Months::new(self.num()))
948                    .ok_or(crate::Error::ParseError),
949                Unit::Year => date
950                    .with_year(date.year() + self.num() as i32)
951                    .ok_or(crate::Error::ParseError),
952                _ => unreachable!(),
953            }
954        }
955    }
956
957    fn before_date(&self, date: ChronoDate) -> Result<ChronoDate, crate::Error> {
958        if self.is_sub_daily() {
959            // TODO: better error
960            return Err(crate::Error::ParseError);
961        }
962
963        if let Duration::Concat(dur1, dur2) = self {
964            return dur2.before_date(dur1.before_date(date)?);
965        }
966
967        if self.convertible() {
968            Ok(date - self.to_chrono())
969        } else {
970            match self.unit() {
971                Unit::Month => date
972                    .checked_sub_months(chrono::Months::new(self.num()))
973                    .ok_or(crate::Error::ParseError),
974                Unit::Year => date
975                    .with_year(date.year() - self.num() as i32)
976                    .ok_or(crate::Error::ParseError),
977                _ => unreachable!(),
978            }
979        }
980    }
981
982    fn is_sub_daily(&self) -> bool {
983        match self {
984            Self::Article(unit) | Self::Specific(_, unit) => match unit {
985                Unit::Day | Unit::Week | Unit::Month | Unit::Year => false,
986                Unit::Hour | Unit::Minute => true,
987            },
988            Self::Concat(a, b) => a.is_sub_daily() || b.is_sub_daily(),
989        }
990    }
991}
992
993#[derive(Debug, Eq, PartialEq, Clone, Copy)]
994pub enum Unit {
995    Day,
996    Week,
997    Hour,
998    Minute,
999    Month,
1000    Year,
1001}
1002
1003impl Unit {
1004    fn parse(l: &[Lexeme]) -> Option<(Self, usize)> {
1005        match l.first() {
1006            Some(Lexeme::Day) => Some((Unit::Day, 1)),
1007            Some(Lexeme::Week) => Some((Unit::Week, 1)),
1008            Some(Lexeme::Month) => Some((Unit::Month, 1)),
1009            Some(Lexeme::Year) => Some((Unit::Year, 1)),
1010            Some(Lexeme::Minute) => Some((Unit::Minute, 1)),
1011            Some(Lexeme::Hour) => Some((Unit::Hour, 1)),
1012            _ => None,
1013        }
1014    }
1015}
1016
1017struct Ones;
1018
1019impl Ones {
1020    fn parse(l: &[Lexeme]) -> Option<(u32, usize)> {
1021        let mut tokens = 1; // starting at 1 because we'll either match one token or return None
1022        if let Some(Lexeme::ST | Lexeme::RD | Lexeme::ND | Lexeme::TH) = l.get(1) {
1023            tokens += 1;
1024        }
1025        match l.first() {
1026            Some(Lexeme::One) => Some((1, tokens)),
1027            Some(Lexeme::Two) => Some((2, tokens)),
1028            Some(Lexeme::Three) => Some((3, tokens)),
1029            Some(Lexeme::Four) => Some((4, tokens)),
1030            Some(Lexeme::Five) => Some((5, tokens)),
1031            Some(Lexeme::Six) => Some((6, tokens)),
1032            Some(Lexeme::Seven) => Some((7, tokens)),
1033            Some(Lexeme::Eight) => Some((8, tokens)),
1034            Some(Lexeme::Nine) => Some((9, tokens)),
1035            Some(Lexeme::Num(num)) if *num < 10 => Some((*num, tokens)),
1036            _ => None,
1037        }
1038    }
1039}
1040
1041struct Teens;
1042impl Teens {
1043    fn parse(l: &[Lexeme]) -> Option<(u32, usize)> {
1044        let mut tokens = 1;
1045        if let Some(Lexeme::TH) = l.get(1) {
1046            tokens += 1;
1047        }
1048        match l.first() {
1049            Some(Lexeme::Ten) => Some((10, tokens)),
1050            Some(Lexeme::Eleven) => Some((11, tokens)),
1051            Some(Lexeme::Twelve) => Some((12, tokens)),
1052            Some(Lexeme::Thirteen) => Some((13, tokens)),
1053            Some(Lexeme::Fourteen) => Some((14, tokens)),
1054            Some(Lexeme::Fifteen) => Some((15, tokens)),
1055            Some(Lexeme::Sixteen) => Some((16, tokens)),
1056            Some(Lexeme::Seventeen) => Some((17, tokens)),
1057            Some(Lexeme::Eighteen) => Some((18, tokens)),
1058            Some(Lexeme::Nineteen) => Some((19, tokens)),
1059            Some(Lexeme::Num(num)) if *num >= 10 && *num < 20 => Some((*num, tokens)),
1060            _ => None,
1061        }
1062    }
1063}
1064
1065struct Tens;
1066impl Tens {
1067    fn parse(l: &[Lexeme]) -> Option<(u32, usize)> {
1068        let mut tokens = 1; // starting at 1 because we'll either match one token or return None
1069        if let Some(Lexeme::TH) = l.get(1) {
1070            tokens += 1;
1071        }
1072
1073        match l.first() {
1074            Some(Lexeme::Twenty) => Some((20, tokens)),
1075            Some(Lexeme::Thirty) => Some((30, tokens)),
1076            Some(Lexeme::Fourty) => Some((40, tokens)),
1077            Some(Lexeme::Fifty) => Some((50, tokens)),
1078            Some(Lexeme::Sixty) => Some((60, tokens)),
1079            Some(Lexeme::Seventy) => Some((70, tokens)),
1080            Some(Lexeme::Eighty) => Some((80, tokens)),
1081            Some(Lexeme::Ninety) => Some((90, tokens)),
1082            _ => None,
1083        }
1084    }
1085}
1086
1087struct NumDouble;
1088impl NumDouble {
1089    fn parse(l: &[Lexeme]) -> Option<(u32, usize)> {
1090        let mut tokens = 0;
1091
1092        if let Some((tens, t)) = Tens::parse(&l[tokens..]) {
1093            tokens += t;
1094
1095            if Some(&Lexeme::Dash) == l.get(tokens) {
1096                tokens += 1;
1097            }
1098
1099            let (ones, t) = Ones::parse(&l[tokens..]).unwrap_or((0, 0));
1100            tokens += t;
1101            return Some((tens + ones, tokens));
1102        }
1103
1104        tokens = 0;
1105        if let Some((teens, t)) = Teens::parse(&l[tokens..]) {
1106            tokens += t;
1107            return Some((teens, tokens));
1108        }
1109
1110        tokens = 0;
1111        if let Some((ones, t)) = Ones::parse(&l[tokens..]) {
1112            tokens += t;
1113            return Some((ones, tokens));
1114        }
1115
1116        tokens = 0;
1117        if let Some(Lexeme::Num(n)) = l.get(tokens) {
1118            tokens += 1;
1119            if *n < 100 && *n > 19 {
1120                return Some((*n, tokens));
1121            }
1122        }
1123
1124        None
1125    }
1126}
1127
1128struct NumTriple;
1129impl NumTriple {
1130    fn parse(l: &[Lexeme]) -> Option<(u32, usize)> {
1131        let mut tokens = 0;
1132        if let Some((ones, t)) = Ones::parse(&l[tokens..]) {
1133            tokens += t;
1134
1135            if Some(&Lexeme::Hundred) == l.get(tokens) {
1136                // Consume 'Hundred'
1137                tokens += 1;
1138
1139                let required = Some(&Lexeme::And) == l.get(tokens);
1140                if required {
1141                    tokens += 1;
1142                }
1143                let double = NumDouble::parse(&l[tokens..]);
1144
1145                if !required || double.is_some() {
1146                    let (double, t) = double.unwrap_or((0, 0));
1147                    tokens += t;
1148
1149                    return Some((ones * 100 + double, tokens));
1150                }
1151            }
1152        }
1153
1154        tokens = 0;
1155        if Some(&Lexeme::Hundred) == l.get(tokens) {
1156            tokens += 1;
1157
1158            let required = Some(&Lexeme::And) == l.get(tokens);
1159            if required {
1160                tokens += 1;
1161            }
1162            let double = NumDouble::parse(&l[tokens..]);
1163
1164            if !required || double.is_some() {
1165                let (double, t) = double.unwrap_or((0, 0));
1166                tokens += t;
1167
1168                return Some((100 + double, tokens));
1169            }
1170        }
1171
1172        tokens = 0;
1173        if let Some((num_double, t)) = NumDouble::parse(&l[tokens..]) {
1174            tokens += t;
1175            return Some((num_double, tokens));
1176        }
1177
1178        // number literal
1179        if let Some(Lexeme::Num(num)) = l.first() {
1180            tokens += 1;
1181            if let Some(Lexeme::ST | Lexeme::RD | Lexeme::ND | Lexeme::TH) = l.get(1) {
1182                tokens += 1;
1183            }
1184
1185            if *num > 99 && *num < 1000 {
1186                return Some((*num, tokens));
1187            }
1188        }
1189        None
1190    }
1191}
1192
1193struct NumTripleUnit;
1194impl NumTripleUnit {
1195    fn parse(l: &[Lexeme]) -> Option<(u32, usize)> {
1196        match l.first() {
1197            Some(Lexeme::Thousand) => Some((1000, 1)),
1198            Some(Lexeme::Million) => Some((1000000, 1)),
1199            Some(Lexeme::Billion) => Some((1000000000, 1)),
1200            _ => None,
1201        }
1202    }
1203}
1204
1205struct Num;
1206impl Num {
1207    fn parse(l: &[Lexeme]) -> Option<(u32, usize)> {
1208        let mut tokens = 0;
1209
1210        // <num_triple>
1211        if let Some((triple, t)) = NumTriple::parse(&l[tokens..]) {
1212            tokens += t;
1213
1214            // <num_triple_unit>
1215            if let Some((unit, t)) = NumTripleUnit::parse(&l[tokens..]) {
1216                tokens += t;
1217
1218                let required = Some(&Lexeme::And) == l.get(tokens);
1219                if required {
1220                    tokens += 1;
1221                } // Consume and
1222                let num = Num::parse(&l[tokens..]);
1223
1224                if !required || num.is_some() {
1225                    let (num, t) = num.unwrap_or((0, 0));
1226                    tokens += t;
1227
1228                    return Some((triple * unit + num, tokens));
1229                }
1230            }
1231        }
1232
1233        tokens = 0;
1234        // <num_triple_unit>
1235        if let Some((unit, t)) = NumTripleUnit::parse(&l[tokens..]) {
1236            tokens += t;
1237
1238            let required = Some(&Lexeme::And) == l.get(tokens);
1239            if required {
1240                tokens += 1;
1241            } // Consume and
1242            let num = Num::parse(&l[tokens..]);
1243
1244            if num.is_some() || !required {
1245                let (num, t) = num.unwrap_or((0, 0));
1246                tokens += t;
1247
1248                return Some((unit + num, tokens));
1249            }
1250        }
1251
1252        // <num_triple>
1253        tokens = 0;
1254        if let Some((num, t)) = NumTriple::parse(&l[tokens..]) {
1255            tokens += t;
1256            return Some((num, tokens));
1257        }
1258
1259        tokens = 0;
1260
1261        // number literal
1262        if let Some(&Lexeme::Num(n)) = l.get(tokens) {
1263            tokens += 1;
1264            if n >= 1000 {
1265                return Some((n, tokens));
1266            }
1267        }
1268
1269        None
1270    }
1271}
1272
1273#[cfg(test)]
1274mod tests {
1275    // TODO: split implementations and tests into separate files
1276
1277    use chrono::{Local, Months, TimeZone};
1278
1279    use crate::ast::*;
1280    use crate::lexer::Lexeme;
1281
1282    #[test]
1283    fn test_ones() {
1284        let lexemes = vec![Lexeme::Five];
1285        let (ones, t) = Ones::parse(lexemes.as_slice()).unwrap();
1286
1287        assert_eq!(ones, 5);
1288        assert_eq!(t, 1);
1289    }
1290
1291    #[test]
1292    fn test_simple_num() {
1293        let lexemes = vec![Lexeme::Num(5)];
1294        let (num, t) = Num::parse(lexemes.as_slice()).unwrap();
1295
1296        assert_eq!(num, 5);
1297        assert_eq!(t, 1);
1298    }
1299
1300    #[test]
1301    fn test_complex_triple_num() {
1302        let lexemes = vec![
1303            Lexeme::Num(2),
1304            Lexeme::Hundred,
1305            Lexeme::And,
1306            Lexeme::Thirty,
1307            Lexeme::Dash,
1308            Lexeme::Five,
1309        ];
1310        let (num, t) = NumTriple::parse(lexemes.as_slice()).unwrap();
1311
1312        assert_eq!(num, 235);
1313        assert_eq!(t, 6);
1314    }
1315
1316    #[test]
1317    fn test_complex_num() {
1318        let lexemes = vec![
1319            Lexeme::Two,
1320            Lexeme::Hundred,
1321            Lexeme::Five,
1322            Lexeme::Million,
1323            Lexeme::Thirty,
1324            Lexeme::Thousand,
1325            Lexeme::And,
1326            Lexeme::Ten,
1327        ];
1328        let (num, t) = Num::parse(lexemes.as_slice()).unwrap();
1329
1330        assert_eq!(t, 8);
1331        assert_eq!(num, 205_030_010);
1332    }
1333
1334    #[test]
1335    fn test_noon_date_time() {
1336        use chrono::Timelike;
1337
1338        let lexemes = vec![
1339            Lexeme::February,
1340            Lexeme::Num(16),
1341            Lexeme::Num(2022),
1342            Lexeme::Noon,
1343        ];
1344        let (date, t) = DateTime::parse(lexemes.as_slice()).unwrap();
1345        let date = date.to_chrono(Local::now()).unwrap();
1346
1347        assert_eq!(t, 4);
1348        assert_eq!(date.year(), 2022);
1349        assert_eq!(date.month(), 2);
1350        assert_eq!(date.day(), 16);
1351        assert_eq!(date.hour(), 12);
1352        assert_eq!(date.minute(), 0);
1353    }
1354
1355    #[test]
1356    fn test_midnight_date_time() {
1357        use chrono::Timelike;
1358
1359        let lexemes = vec![
1360            Lexeme::February,
1361            Lexeme::Num(16),
1362            Lexeme::Num(2022),
1363            Lexeme::Midnight,
1364        ];
1365        let (date, t) = DateTime::parse(lexemes.as_slice()).unwrap();
1366        let date = date.to_chrono(Local::now()).unwrap();
1367
1368        assert_eq!(t, 4);
1369        assert_eq!(date.year(), 2022);
1370        assert_eq!(date.month(), 2);
1371        assert_eq!(date.day(), 16);
1372        assert_eq!(date.hour(), 0);
1373        assert_eq!(date.minute(), 0);
1374    }
1375
1376    #[test]
1377    fn test_simple_date_time() {
1378        use chrono::Timelike;
1379
1380        let lexemes = vec![
1381            Lexeme::February,
1382            Lexeme::Num(16),
1383            Lexeme::Num(2022),
1384            Lexeme::Num(5),
1385            Lexeme::Colon,
1386            Lexeme::Num(27),
1387            Lexeme::PM,
1388        ];
1389        let (parsed, t) = DateTime::parse(lexemes.as_slice()).unwrap();
1390        let result = parsed.to_chrono(Local::now()).unwrap();
1391
1392        assert_eq!(t, 7);
1393        assert_eq!(result.year(), 2022);
1394        assert_eq!(result.month(), 2);
1395        assert_eq!(result.day(), 16);
1396        assert_eq!(result.hour(), 17);
1397        assert_eq!(result.minute(), 27);
1398    }
1399
1400    #[test]
1401    fn test_complex_relative_datetime() {
1402        let lexemes = vec![
1403            Lexeme::A,
1404            Lexeme::Week,
1405            Lexeme::After,
1406            Lexeme::Two,
1407            Lexeme::Day,
1408            Lexeme::Before,
1409            Lexeme::The,
1410            Lexeme::Day,
1411            Lexeme::After,
1412            Lexeme::Tomorrow,
1413            Lexeme::Comma,
1414            Lexeme::Num(5),
1415            Lexeme::Colon,
1416            Lexeme::Num(20),
1417        ];
1418
1419        use chrono::naive::Days;
1420        let now = Local
1421            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1422            .single()
1423            .expect("literal date for test case");
1424        let today = now.date_naive();
1425        let real_date = today + Days::new(7 - 2 + 1 + 1);
1426
1427        let (parsed, t) = DateTime::parse(lexemes.as_slice()).unwrap();
1428        let result = parsed.to_chrono(now).unwrap();
1429
1430        assert_eq!(t, 14);
1431        assert_eq!(result.year(), real_date.year());
1432        assert_eq!(result.month(), real_date.month());
1433        assert_eq!(result.day(), real_date.day());
1434    }
1435
1436    #[test]
1437    fn test_datetime_now() {
1438        use chrono::Timelike;
1439
1440        let lexemes = vec![Lexeme::Now];
1441        let (parsed, t) = DateTime::parse(lexemes.as_slice()).unwrap();
1442        let now = Local
1443            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1444            .single()
1445            .expect("literal date for test case");
1446        let result = parsed.to_chrono(now).unwrap();
1447
1448        assert_eq!(t, 1);
1449        assert_eq!(result.year(), now.year());
1450        assert_eq!(result.month(), now.month());
1451        assert_eq!(result.day(), now.day());
1452        assert_eq!(result.hour(), now.hour());
1453        assert_eq!(result.minute(), now.minute());
1454    }
1455
1456    #[test]
1457    fn test_malformed_article_after() {
1458        let lexemes = vec![Lexeme::A, Lexeme::Day, Lexeme::After, Lexeme::Colon];
1459        assert!(DateTime::parse(lexemes.as_slice()).is_none());
1460    }
1461
1462    #[test]
1463    fn test_malformed_after() {
1464        let lexemes = vec![Lexeme::Num(5), Lexeme::Day, Lexeme::After, Lexeme::Colon];
1465        assert!(DateTime::parse(lexemes.as_slice()).is_none());
1466    }
1467
1468    #[test]
1469    fn test_datetime_ago() {
1470        let lexemes = vec![Lexeme::A, Lexeme::Day, Lexeme::Ago];
1471        let now = Local
1472            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1473            .single()
1474            .expect("literal date for test case");
1475        let (parsed, t) = DateTime::parse(lexemes.as_slice()).unwrap();
1476        let result = parsed.to_chrono(now).unwrap();
1477
1478        let today = now.date_naive();
1479        assert_eq!(t, 3);
1480        assert_eq!(result.year(), today.year());
1481        assert_eq!(result.month(), today.month());
1482        assert_eq!(result.day(), today.day() - 1);
1483    }
1484
1485    #[test]
1486    fn test_teens() {
1487        assert_eq!((10, 1), Teens::parse(&[Lexeme::Ten]).unwrap());
1488        assert_eq!((11, 1), Teens::parse(&[Lexeme::Eleven]).unwrap());
1489        assert_eq!((12, 1), Teens::parse(&[Lexeme::Twelve]).unwrap());
1490        assert_eq!((13, 1), Teens::parse(&[Lexeme::Thirteen]).unwrap());
1491        assert_eq!((14, 1), Teens::parse(&[Lexeme::Fourteen]).unwrap());
1492        assert_eq!((15, 1), Teens::parse(&[Lexeme::Fifteen]).unwrap());
1493        assert_eq!((16, 1), Teens::parse(&[Lexeme::Sixteen]).unwrap());
1494        assert_eq!((17, 1), Teens::parse(&[Lexeme::Seventeen]).unwrap());
1495        assert_eq!((18, 1), Teens::parse(&[Lexeme::Eighteen]).unwrap());
1496        assert_eq!((19, 1), Teens::parse(&[Lexeme::Nineteen]).unwrap());
1497    }
1498
1499    #[test]
1500    fn test_article_before() {
1501        let now = Local
1502            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1503            .single()
1504            .expect("literal date for test case");
1505        let (parsed, t) =
1506            DateTime::parse(&[Lexeme::A, Lexeme::Day, Lexeme::Before, Lexeme::Today]).unwrap();
1507        let result = parsed.to_chrono(now).unwrap();
1508
1509        let today = now.date_naive();
1510        assert_eq!(t, 4);
1511        assert_eq!(result.year(), today.year());
1512        assert_eq!(result.month(), today.month());
1513        assert_eq!(result.day(), today.day() - 1);
1514    }
1515
1516    #[test]
1517    fn test_after_december() {
1518        let l = vec![
1519            Lexeme::A,
1520            Lexeme::Month,
1521            Lexeme::After,
1522            Lexeme::December,
1523            Lexeme::Num(5),
1524        ];
1525        let now = Local
1526            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1527            .single()
1528            .expect("literal date for test case");
1529
1530        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1531        let date = date.to_chrono(now).unwrap();
1532
1533        assert_eq!(t, 5);
1534        assert_eq!(date.year(), now.year() + 1);
1535        assert_eq!(date.month(), 1);
1536        assert_eq!(date.day(), 5);
1537    }
1538
1539    #[test]
1540    fn test_month_before_january() {
1541        let l = vec![
1542            Lexeme::A,
1543            Lexeme::Month,
1544            Lexeme::Before,
1545            Lexeme::January,
1546            Lexeme::Num(5),
1547        ];
1548
1549        let now = Local
1550            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1551            .single()
1552            .expect("literal date for test case");
1553
1554        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1555        let date = date.to_chrono(now).unwrap();
1556
1557        assert_eq!(t, 5);
1558        assert_eq!(date.year(), now.year() - 1);
1559        assert_eq!(date.month(), 12);
1560        assert_eq!(date.day(), 5);
1561    }
1562
1563    #[test]
1564    fn test_month_day() {
1565        let l = vec![Lexeme::February, Lexeme::Num(5)];
1566        let now = Local
1567            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1568            .single()
1569            .expect("literal date for test case");
1570
1571        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1572        let date = date.to_chrono(now).unwrap();
1573
1574        assert_eq!(t, 2);
1575        assert_eq!(date.year(), now.year());
1576        assert_eq!(date.month(), 2);
1577        assert_eq!(date.day(), 5);
1578    }
1579
1580    #[test]
1581    fn test_month_day_year() {
1582        let l = vec![Lexeme::February, Lexeme::Num(5), Lexeme::Num(2024)];
1583        let now = Local
1584            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1585            .single()
1586            .expect("literal date for test case");
1587
1588        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1589        let date = date.to_chrono(now).unwrap();
1590
1591        assert_eq!(t, 3);
1592        assert_eq!(date.year(), 2024);
1593        assert_eq!(date.month(), 2);
1594        assert_eq!(date.day(), 5);
1595    }
1596
1597    #[test]
1598    fn test_day_month_year() {
1599        let l = vec![Lexeme::Num(17), Lexeme::February, Lexeme::Num(2027)];
1600        let now = Local
1601            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1602            .single()
1603            .expect("literal date for test case");
1604
1605        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1606        let date = date.to_chrono(now).unwrap();
1607
1608        assert_eq!(t, 3);
1609        assert_eq!(date.year(), 2027);
1610        assert_eq!(date.month(), 2);
1611        assert_eq!(date.day(), 17);
1612    }
1613
1614    #[test]
1615    fn test_month_after() {
1616        let l = vec![
1617            Lexeme::A,
1618            Lexeme::Month,
1619            Lexeme::After,
1620            Lexeme::October,
1621            Lexeme::Num(5),
1622        ];
1623        let now = Local
1624            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1625            .single()
1626            .expect("literal date for test case");
1627
1628        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1629        let date = date.to_chrono(now).unwrap();
1630
1631        assert_eq!(t, 5);
1632        assert_eq!(date.year(), now.year());
1633        assert_eq!(date.month(), 11);
1634        assert_eq!(date.day(), 5);
1635    }
1636
1637    #[test]
1638    fn test_year_after() {
1639        let l = vec![
1640            Lexeme::A,
1641            Lexeme::Year,
1642            Lexeme::After,
1643            Lexeme::October,
1644            Lexeme::Num(5),
1645        ];
1646
1647        let now = Local
1648            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1649            .single()
1650            .expect("literal date for test case");
1651
1652        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1653        let date = date.to_chrono(now).unwrap();
1654
1655        assert_eq!(t, 5);
1656        assert_eq!(date.year(), now.year() + 1);
1657        assert_eq!(date.month(), 10);
1658        assert_eq!(date.day(), 5);
1659    }
1660
1661    #[test]
1662    fn test_month_before() {
1663        let l = vec![
1664            Lexeme::A,
1665            Lexeme::Month,
1666            Lexeme::Before,
1667            Lexeme::October,
1668            Lexeme::Num(5),
1669        ];
1670
1671        let now = Local
1672            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1673            .single()
1674            .expect("literal date for test case");
1675        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1676        let date = date.to_chrono(now).unwrap();
1677
1678        assert_eq!(t, 5);
1679        assert_eq!(date.year(), now.year());
1680        assert_eq!(date.month(), 9);
1681        assert_eq!(date.day(), 5);
1682    }
1683
1684    #[test]
1685    fn test_year_before() {
1686        let l = vec![
1687            Lexeme::A,
1688            Lexeme::Year,
1689            Lexeme::Before,
1690            Lexeme::October,
1691            Lexeme::Num(5),
1692        ];
1693        let now = Local
1694            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
1695            .single()
1696            .expect("literal date for test case");
1697        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1698        let date = date.to_chrono(now).unwrap();
1699
1700        assert_eq!(t, 5);
1701        assert_eq!(date.year(), now.year() - 1);
1702        assert_eq!(date.month(), 10);
1703        assert_eq!(date.day(), 5);
1704    }
1705
1706    #[test]
1707    fn test_month_before_to_leap_day() {
1708        let l = vec![
1709            Lexeme::Num(3),
1710            Lexeme::Month,
1711            Lexeme::Before,
1712            Lexeme::May,
1713            Lexeme::Num(31),
1714            Lexeme::Num(2024),
1715        ];
1716
1717        let now = Local::now();
1718        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1719        let date = date.to_chrono(now).unwrap();
1720
1721        assert_eq!(t, 6);
1722        assert_eq!(date.year(), 2024);
1723        assert_eq!(date.month(), 2);
1724        // 2024 is a leap year
1725        assert_eq!(date.day(), 29);
1726    }
1727
1728    #[test]
1729    fn test_month_before_invalid_date() {
1730        let l = vec![
1731            Lexeme::Num(3),
1732            Lexeme::Month,
1733            Lexeme::Before,
1734            Lexeme::May,
1735            Lexeme::Num(31),
1736            Lexeme::Num(2023),
1737        ];
1738
1739        let now = Local::now();
1740        let (date, t) = DateTime::parse(l.as_slice()).unwrap();
1741        let date = date.to_chrono(now).unwrap();
1742
1743        assert_eq!(t, 6);
1744        assert_eq!(date.year(), 2023);
1745        assert_eq!(date.month(), 2);
1746        // 2024 is a leap year
1747        assert_eq!(date.day(), 28);
1748    }
1749
1750    #[test]
1751    fn test_next_weekday_from_week_start() {
1752        let l = vec![Lexeme::Next, Lexeme::Monday];
1753
1754        // 12 Apr 2021 is a Monday
1755        let now = Local
1756            .with_ymd_and_hms(2021, 4, 12, 7, 15, 17)
1757            .single()
1758            .expect("literal datetime for test case");
1759        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1760
1761        let expected = Local
1762            .with_ymd_and_hms(2021, 4, 19, 7, 15, 17)
1763            .single()
1764            .expect("literal datetime for test case");
1765        let date = date.to_chrono(now).unwrap();
1766
1767        assert_eq!(date, expected);
1768    }
1769
1770    #[test]
1771    fn test_next_weekday_from_week_end() {
1772        let l = vec![Lexeme::Next, Lexeme::Monday];
1773
1774        // 18 Apr 2021 is a Sunday
1775        let now = Local
1776            .with_ymd_and_hms(2021, 4, 18, 7, 15, 17)
1777            .single()
1778            .expect("literal datetime for test case");
1779        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1780
1781        let expected = Local
1782            .with_ymd_and_hms(2021, 4, 19, 7, 15, 17)
1783            .single()
1784            .expect("literal datetime for test case");
1785        let date = date.to_chrono(now).unwrap();
1786
1787        assert_eq!(date, expected);
1788    }
1789
1790    #[test]
1791    fn test_last_weekday_from_week_start() {
1792        let l = vec![Lexeme::Last, Lexeme::Monday];
1793
1794        // 12 Apr 2021 is a Monday
1795        let now = Local
1796            .with_ymd_and_hms(2021, 4, 12, 7, 15, 17)
1797            .single()
1798            .expect("literal datetime for test case");
1799        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1800
1801        let expected = Local
1802            .with_ymd_and_hms(2021, 4, 5, 7, 15, 17)
1803            .single()
1804            .expect("literal datetime for test case");
1805        let date = date.to_chrono(now).unwrap();
1806
1807        assert_eq!(date, expected);
1808    }
1809
1810    #[test]
1811    fn test_last_weekday_from_week_end() {
1812        let l = vec![Lexeme::Last, Lexeme::Monday];
1813
1814        // 18 Apr 2021 is a Sunday
1815        let now = Local
1816            .with_ymd_and_hms(2021, 4, 18, 7, 15, 17)
1817            .single()
1818            .expect("literal datetime for test case");
1819        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1820
1821        let expected = Local
1822            .with_ymd_and_hms(2021, 4, 5, 7, 15, 17)
1823            .single()
1824            .expect("literal datetime for test case");
1825        let date = date.to_chrono(now).unwrap();
1826
1827        assert_eq!(date, expected);
1828    }
1829
1830    #[test]
1831    fn test_this_weekday_from_week_start() {
1832        let l = vec![Lexeme::This, Lexeme::Monday];
1833
1834        // 12 Apr 2021 is a Monday
1835        let now = Local
1836            .with_ymd_and_hms(2021, 4, 12, 7, 15, 17)
1837            .single()
1838            .expect("literal datetime for test case");
1839        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1840
1841        let expected = Local
1842            .with_ymd_and_hms(2021, 4, 12, 7, 15, 17)
1843            .single()
1844            .expect("literal datetime for test case");
1845        let date = date.to_chrono(now).unwrap();
1846
1847        assert_eq!(date, expected);
1848    }
1849
1850    #[test]
1851    fn test_this_weekday_from_week_end() {
1852        let l = vec![Lexeme::This, Lexeme::Monday];
1853
1854        // 18 Apr 2021 is a Sunday
1855        let now = Local
1856            .with_ymd_and_hms(2021, 4, 18, 7, 15, 17)
1857            .single()
1858            .expect("literal datetime for test case");
1859        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1860
1861        let expected = Local
1862            .with_ymd_and_hms(2021, 4, 12, 7, 15, 17)
1863            .single()
1864            .expect("literal datetime for test case");
1865        let date = date.to_chrono(now).unwrap();
1866
1867        assert_eq!(date, expected);
1868    }
1869
1870    #[test]
1871    fn test_next_week() {
1872        let l = vec![Lexeme::Next, Lexeme::Week];
1873
1874        let now = Local::now();
1875        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1876        let date = date.to_chrono(now).unwrap();
1877
1878        assert_eq!(date, now + ChronoDuration::weeks(1));
1879    }
1880
1881    #[test]
1882    fn test_next_month() {
1883        let l = vec![Lexeme::Next, Lexeme::Month];
1884
1885        let now = Local::now();
1886        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1887        let date = date.to_chrono(now).unwrap();
1888
1889        assert_eq!(
1890            date,
1891            now.checked_add_months(chrono::Months::new(1))
1892                .expect("Adding one month to current date shouldn't be the end of time.")
1893        );
1894    }
1895
1896    #[test]
1897    fn test_next_year() {
1898        let l = vec![Lexeme::Next, Lexeme::Year];
1899
1900        let now = Local::now();
1901        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1902        let date = date.to_chrono(now).unwrap();
1903
1904        assert_eq!(
1905            date,
1906            now.with_year(now.year() + 1)
1907                .expect("Adding one year to current date shouldn't be the end of time.")
1908        );
1909    }
1910
1911    #[test]
1912    fn test_last_week() {
1913        let l = vec![Lexeme::Last, Lexeme::Week];
1914
1915        let now = Local::now();
1916        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1917        let date = date.to_chrono(now).unwrap();
1918
1919        assert_eq!(date, now - ChronoDuration::weeks(1));
1920    }
1921
1922    #[test]
1923    fn test_last_month() {
1924        let l = vec![Lexeme::Last, Lexeme::Month];
1925
1926        let now = Local::now();
1927        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1928        let date = date.to_chrono(now).unwrap();
1929
1930        assert_eq!(
1931            date,
1932            now.checked_sub_months(chrono::Months::new(1))
1933                .expect("Subtracting one month to current date shouldn't be the end of time.")
1934        );
1935    }
1936
1937    #[test]
1938    fn test_last_year() {
1939        let l = vec![Lexeme::Last, Lexeme::Year];
1940
1941        let now = Local::now();
1942        let (date, _) = DateTime::parse(l.as_slice()).unwrap();
1943        let date = date.to_chrono(now).unwrap();
1944
1945        assert_eq!(
1946            date,
1947            now.with_year(now.year() - 1)
1948                .expect("Subtracting one year to current date shouldn't be the end of time.")
1949        );
1950    }
1951
1952    #[test]
1953    fn test_month_literals_with_time_and_year() {
1954        use chrono::Timelike;
1955
1956        let lexemes = vec![
1957            Lexeme::February,
1958            Lexeme::Num(16),
1959            Lexeme::Num(2022),
1960            Lexeme::Comma,
1961            Lexeme::Num(5),
1962            Lexeme::Colon,
1963            Lexeme::Num(27),
1964            Lexeme::PM,
1965        ];
1966
1967        let now = Local::now();
1968        let (date, t) = DateTime::parse(lexemes.as_slice()).unwrap();
1969        let date = date.to_chrono(now).unwrap();
1970
1971        assert_eq!(t, 8);
1972        assert_eq!(date.year(), 2022);
1973        assert_eq!(date.month(), 2);
1974        assert_eq!(date.day(), 16);
1975        assert_eq!(date.hour(), 17);
1976        assert_eq!(date.minute(), 27);
1977    }
1978
1979    #[test]
1980    fn test_slash_separated_date() {
1981        let lexemes = vec![
1982            Lexeme::Num(5),
1983            Lexeme::Slash,
1984            Lexeme::Num(12),
1985            Lexeme::Slash,
1986            Lexeme::Num(2023),
1987        ];
1988
1989        let now = Local::now();
1990        let (date, t) = DateTime::parse(lexemes.as_slice()).unwrap();
1991        let date = date.to_chrono(now).unwrap();
1992
1993        assert_eq!(t, 5);
1994        assert_eq!(date.year(), 2023);
1995        assert_eq!(date.month(), 5);
1996        assert_eq!(date.day(), 12);
1997    }
1998
1999    #[test]
2000    fn test_month_literals_with_time_and_no_year() {
2001        use chrono::Timelike;
2002
2003        let lexemes = vec![
2004            Lexeme::February,
2005            Lexeme::Num(16),
2006            Lexeme::Comma,
2007            Lexeme::Num(5),
2008            Lexeme::Colon,
2009            Lexeme::Num(27),
2010            Lexeme::PM,
2011        ];
2012
2013        let now = Local::now();
2014        let (date, t) = DateTime::parse(lexemes.as_slice()).unwrap();
2015        let date = date.to_chrono(now).unwrap();
2016        let current_year = Local::now().naive_local().year();
2017
2018        assert_eq!(t, 7);
2019        assert_eq!(date.year(), current_year);
2020        assert_eq!(date.month(), 2);
2021        assert_eq!(date.day(), 16);
2022        assert_eq!(date.hour(), 17);
2023        assert_eq!(date.minute(), 27);
2024    }
2025
2026    #[test]
2027    fn test_slash_separated_invalid_month() {
2028        let lexemes = vec![
2029            Lexeme::Num(13),
2030            Lexeme::Slash,
2031            Lexeme::Num(12),
2032            Lexeme::Slash,
2033            Lexeme::Num(2023),
2034        ];
2035
2036        let now = Local::now();
2037        let (date, _) = DateTime::parse(lexemes.as_slice()).unwrap();
2038        let date = date.to_chrono(now);
2039
2040        assert!(date.is_err());
2041    }
2042
2043    #[test]
2044    fn test_dash_separated_date() {
2045        let lexemes = vec![
2046            Lexeme::Num(5),
2047            Lexeme::Dash,
2048            Lexeme::Num(12),
2049            Lexeme::Dash,
2050            Lexeme::Num(2023),
2051        ];
2052        let now = Local::now();
2053        let (date, t) = DateTime::parse(lexemes.as_slice()).unwrap();
2054        let date = date.to_chrono(now).unwrap();
2055
2056        assert_eq!(t, 5);
2057        assert_eq!(date.year(), 2023);
2058        assert_eq!(date.month(), 5);
2059        assert_eq!(date.day(), 12);
2060    }
2061
2062    #[test]
2063    fn test_dash_separated_invalid_month() {
2064        let lexemes = vec![
2065            Lexeme::Num(13),
2066            Lexeme::Dash,
2067            Lexeme::Num(12),
2068            Lexeme::Dash,
2069            Lexeme::Num(2023),
2070        ];
2071        let now = Local::now();
2072        let (date, _) = DateTime::parse(lexemes.as_slice()).unwrap();
2073        let date = date.to_chrono(now);
2074
2075        assert!(date.is_err());
2076    }
2077
2078    #[test]
2079    fn test_dot_separated_date() {
2080        let lexemes = vec![
2081            Lexeme::Num(19),
2082            Lexeme::Dot,
2083            Lexeme::Num(12),
2084            Lexeme::Dot,
2085            Lexeme::Num(2023),
2086        ];
2087        let now = Local::now();
2088        let (date, t) = DateTime::parse(lexemes.as_slice()).unwrap();
2089        let date = date.to_chrono(now).unwrap();
2090
2091        assert_eq!(t, 5);
2092        assert_eq!(date.year(), 2023);
2093        assert_eq!(date.month(), 12);
2094        assert_eq!(date.day(), 19);
2095    }
2096
2097    #[test]
2098    fn test_slash_separated_date_year_first() {
2099        let lexemes = vec![
2100            Lexeme::Num(2023),
2101            Lexeme::Slash,
2102            Lexeme::Num(5),
2103            Lexeme::Slash,
2104            Lexeme::Num(12),
2105        ];
2106
2107        let now = Local::now();
2108        let (date, t) = DateTime::parse(lexemes.as_slice()).unwrap();
2109        let date = date.to_chrono(now).unwrap();
2110
2111        assert_eq!(t, 5);
2112        assert_eq!(date.year(), 2023);
2113        assert_eq!(date.month(), 5);
2114        assert_eq!(date.day(), 12);
2115    }
2116
2117    #[test]
2118    fn test_dash_separated_date_year_first() {
2119        let lexemes = vec![
2120            Lexeme::Num(2023),
2121            Lexeme::Dash,
2122            Lexeme::Num(5),
2123            Lexeme::Dash,
2124            Lexeme::Num(12),
2125        ];
2126
2127        let now = Local::now();
2128        let (date, t) = DateTime::parse(lexemes.as_slice()).unwrap();
2129        let date = date.to_chrono(now).unwrap();
2130
2131        assert_eq!(t, 5);
2132        assert_eq!(date.year(), 2023);
2133        assert_eq!(date.month(), 5);
2134        assert_eq!(date.day(), 12);
2135    }
2136
2137    #[test]
2138    fn test_dot_separated_date_year_first() {
2139        let lexemes = vec![
2140            Lexeme::Num(2023),
2141            Lexeme::Dot,
2142            Lexeme::Num(5),
2143            Lexeme::Dot,
2144            Lexeme::Num(12),
2145        ];
2146
2147        let now = Local::now();
2148        let (date, t) = DateTime::parse(lexemes.as_slice()).unwrap();
2149        let date = date.to_chrono(now).unwrap();
2150
2151        assert_eq!(t, 5);
2152        assert_eq!(date.year(), 2023);
2153        assert_eq!(date.month(), 5);
2154        assert_eq!(date.day(), 12);
2155    }
2156
2157    #[test]
2158    fn test_dot_separated_date_invalid_month() {
2159        let lexemes = vec![
2160            Lexeme::Num(19),
2161            Lexeme::Dot,
2162            Lexeme::Num(13),
2163            Lexeme::Dot,
2164            Lexeme::Num(2023),
2165        ];
2166        let now = Local::now();
2167        let (date, _) = DateTime::parse(lexemes.as_slice()).unwrap();
2168        let date = date.to_chrono(now);
2169
2170        assert!(date.is_err());
2171    }
2172
2173    #[test]
2174    fn test_date_day_ago() {
2175        let lexemes = vec![Lexeme::Num(3), Lexeme::Day, Lexeme::Ago];
2176        let now = Local
2177            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
2178            .single()
2179            .expect("literal date for test case");
2180        let (date, tokens) = DateTime::parse(lexemes.as_slice()).unwrap();
2181        let date = date.to_chrono(now);
2182
2183        let date = date.unwrap();
2184
2185        assert_eq!(tokens, 3);
2186
2187        assert_eq!(
2188            now.date_naive() - date.date_naive(),
2189            ChronoDuration::days(3)
2190        );
2191        assert_eq!(now.time(), date.time());
2192    }
2193
2194    #[test]
2195    fn test_date_day_after() {
2196        let lexemes = vec![Lexeme::Num(3), Lexeme::Day, Lexeme::After, Lexeme::Now];
2197        let now = Local
2198            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
2199            .single()
2200            .expect("literal date for test case");
2201
2202        let (date, tokens) = DateTime::parse(lexemes.as_slice()).unwrap();
2203        let date = date.to_chrono(now);
2204
2205        let date = date.unwrap();
2206
2207        assert_eq!(tokens, 4);
2208
2209        assert_eq!(
2210            date.date_naive() - now.date_naive(),
2211            ChronoDuration::days(3)
2212        );
2213        assert_eq!(now.time(), date.time());
2214    }
2215
2216    #[test]
2217    fn test_date_day_before() {
2218        let lexemes = vec![Lexeme::Num(3), Lexeme::Day, Lexeme::Before, Lexeme::Now];
2219        let now = Local
2220            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
2221            .single()
2222            .expect("literal date for test case");
2223
2224        let (date, tokens) = DateTime::parse(lexemes.as_slice()).unwrap();
2225        let date = date.to_chrono(now);
2226
2227        let date = date.unwrap();
2228
2229        assert_eq!(tokens, 4);
2230
2231        assert_eq!(
2232            now.date_naive() - ChronoDuration::days(3),
2233            date.date_naive()
2234        );
2235
2236        assert_eq!(now.time(), date.time());
2237    }
2238
2239    #[test]
2240    fn test_date_month_after() {
2241        let lexemes = vec![Lexeme::Num(3), Lexeme::Month, Lexeme::After, Lexeme::Now];
2242        let now = Local
2243            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
2244            .single()
2245            .expect("literal date for test case");
2246
2247        let (date, tokens) = DateTime::parse(lexemes.as_slice()).unwrap();
2248        let date = date.to_chrono(now);
2249
2250        let date = date.unwrap();
2251
2252        assert_eq!(tokens, 4);
2253
2254        assert_eq!(
2255            now.date_naive().checked_add_months(Months::new(3)).unwrap(),
2256            date.date_naive()
2257        );
2258        assert_eq!(now.time(), date.time());
2259    }
2260
2261    #[test]
2262    fn test_date_month_before() {
2263        let lexemes = vec![Lexeme::Num(3), Lexeme::Month, Lexeme::Before, Lexeme::Now];
2264        let now = Local
2265            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
2266            .single()
2267            .expect("literal date for test case");
2268
2269        let (date, tokens) = DateTime::parse(lexemes.as_slice()).unwrap();
2270        let date = date.to_chrono(now);
2271
2272        let date = date.unwrap();
2273
2274        assert_eq!(tokens, 4);
2275
2276        assert_eq!(
2277            now.date_naive().checked_sub_months(Months::new(3)).unwrap(),
2278            date.date_naive()
2279        );
2280        assert_eq!(now.time(), date.time());
2281    }
2282
2283    #[test]
2284    fn test_date_minute_after() {
2285        let lexemes = vec![
2286            Lexeme::Num(3),
2287            Lexeme::Minute,
2288            Lexeme::After,
2289            Lexeme::Yesterday,
2290        ];
2291        // Duration with sub-daily unit should not be parsed as a Date expression
2292        // so Date::parse should return None.
2293        assert!(Date::parse(lexemes.as_slice()).is_none());
2294    }
2295
2296    #[test]
2297    fn test_date_minute_before() {
2298        let lexemes = vec![
2299            Lexeme::Num(3),
2300            Lexeme::Minute,
2301            Lexeme::Before,
2302            Lexeme::Yesterday,
2303        ];
2304        // Duration with sub-daily unit should not be parsed as a Date expression
2305        // so Date::parse should return None.
2306        assert!(Date::parse(lexemes.as_slice()).is_none());
2307    }
2308
2309    #[test]
2310    fn test_march_dst_transition() {
2311        // March DST transition in America/New_York creates a non-existent local time
2312        use chrono_tz::America::New_York;
2313
2314        let lexemes = vec![
2315            Lexeme::March,
2316            Lexeme::Num(14),
2317            Lexeme::Num(2021),
2318            Lexeme::Num(2),
2319            Lexeme::Colon,
2320            Lexeme::Num(30),
2321        ];
2322
2323        let now = New_York.with_ymd_and_hms(2021, 3, 14, 12, 0, 0).unwrap();
2324        let (parsed, _) = DateTime::parse(lexemes.as_slice()).unwrap();
2325        let res = parsed.to_chrono(now);
2326
2327        // 2:30 on this date in New York is a nonexistent local time -> conversion fails
2328        assert!(res.is_err());
2329    }
2330
2331    #[test]
2332    fn test_november_dst_transition() {
2333        // November DST transition in America/New_York repeats the 1 AM hour.
2334        // We should pick the earlier of the two.
2335        use chrono_tz::America::New_York;
2336
2337        let lexemes = vec![
2338            Lexeme::November,
2339            Lexeme::Num(7),
2340            Lexeme::Num(2021),
2341            Lexeme::Num(1),
2342            Lexeme::Colon,
2343            Lexeme::Num(30),
2344            Lexeme::AM,
2345        ];
2346
2347        let now = New_York.with_ymd_and_hms(2021, 11, 7, 12, 0, 0).unwrap();
2348        let (parsed, _) = DateTime::parse(lexemes.as_slice()).unwrap();
2349        let res = parsed.to_chrono(now).unwrap();
2350
2351        // Earlier 1:30 on this date is during DST (UTC-4) => offset (local - utc) should be -14400
2352        assert_eq!(
2353            res.naive_local()
2354                .signed_duration_since(res.naive_utc())
2355                .num_seconds(),
2356            -4 * 3600
2357        );
2358    }
2359
2360    #[test]
2361    fn test_return_correct_timezone_dst() {
2362        // Adding an hour across the spring-forward DST boundary should succeed for
2363        // convertible durations (hours) and result in the correct local time in the
2364        // timezone of `now`
2365        use chrono::Timelike;
2366        use chrono_tz::America::New_York;
2367
2368        let lexemes = vec![
2369            Lexeme::A,
2370            Lexeme::Hour,
2371            Lexeme::After,
2372            Lexeme::March,
2373            Lexeme::Num(14),
2374            Lexeme::Num(2021),
2375            Lexeme::Num(1),
2376            Lexeme::Colon,
2377            Lexeme::Num(30),
2378        ];
2379
2380        let now = New_York.with_ymd_and_hms(2021, 3, 14, 12, 0, 0).unwrap();
2381        let (parsed, _) = DateTime::parse(lexemes.as_slice()).unwrap();
2382        let res = parsed.to_chrono(now).unwrap();
2383
2384        assert_eq!(res.hour(), 3);
2385        assert_eq!(res.minute(), 30);
2386        assert_eq!(
2387            res.naive_local()
2388                .signed_duration_since(res.naive_utc())
2389                .num_seconds(),
2390            -4 * 3600
2391        );
2392    }
2393
2394    #[test]
2395    fn test_datetime_duration_minutes() {
2396        let lexemes = vec![Lexeme::Num(3), Lexeme::Minute, Lexeme::Before, Lexeme::Now];
2397        let now = Local
2398            .with_ymd_and_hms(2021, 4, 30, 7, 15, 17)
2399            .single()
2400            .expect("literal date for test case");
2401
2402        let (date, tokens) = DateTime::parse(lexemes.as_slice()).unwrap();
2403        let date = date.to_chrono(now);
2404        let date = date.unwrap();
2405
2406        assert_eq!(tokens, 4);
2407        assert_eq!(now - date, chrono::Duration::minutes(3));
2408    }
2409
2410    #[test]
2411    fn test_duration_sub_daily_specific() {
2412        assert!(!Duration::Specific(2, Unit::Day).is_sub_daily());
2413        assert!(!Duration::Specific(2, Unit::Week).is_sub_daily());
2414        assert!(!Duration::Specific(2, Unit::Month).is_sub_daily());
2415        assert!(!Duration::Specific(2, Unit::Year).is_sub_daily());
2416        assert!(Duration::Specific(2, Unit::Hour).is_sub_daily());
2417        assert!(Duration::Specific(2, Unit::Minute).is_sub_daily());
2418    }
2419
2420    #[test]
2421    fn test_duration_sub_daily_article() {
2422        assert!(!Duration::Article(Unit::Day).is_sub_daily());
2423        assert!(!Duration::Article(Unit::Week).is_sub_daily());
2424        assert!(!Duration::Article(Unit::Month).is_sub_daily());
2425        assert!(!Duration::Article(Unit::Year).is_sub_daily());
2426        assert!(Duration::Article(Unit::Hour).is_sub_daily());
2427        assert!(Duration::Article(Unit::Minute).is_sub_daily());
2428    }
2429
2430    #[test]
2431    fn test_duration_sub_daily_concat() {
2432        assert!(!Duration::Concat(
2433            Box::new(Duration::Specific(3, Unit::Day)),
2434            Box::new(Duration::Specific(1, Unit::Year))
2435        )
2436        .is_sub_daily());
2437
2438        assert!(!Duration::Concat(
2439            Box::new(Duration::Specific(3, Unit::Day)),
2440            Box::new(Duration::Specific(1, Unit::Week))
2441        )
2442        .is_sub_daily());
2443
2444        assert!(!Duration::Concat(
2445            Box::new(Duration::Specific(3, Unit::Week)),
2446            Box::new(Duration::Specific(1, Unit::Year))
2447        )
2448        .is_sub_daily());
2449
2450        assert!(!Duration::Concat(
2451            Box::new(Duration::Specific(1, Unit::Day)),
2452            Box::new(Duration::Concat(
2453                Box::new(Duration::Specific(2, Unit::Week)),
2454                Box::new(Duration::Specific(3, Unit::Year))
2455            ))
2456        )
2457        .is_sub_daily());
2458
2459        assert!(Duration::Concat(
2460            Box::new(Duration::Specific(3, Unit::Hour)),
2461            Box::new(Duration::Specific(1, Unit::Minute))
2462        )
2463        .is_sub_daily());
2464
2465        assert!(Duration::Concat(
2466            Box::new(Duration::Specific(3, Unit::Day)),
2467            Box::new(Duration::Specific(1, Unit::Hour))
2468        )
2469        .is_sub_daily());
2470
2471        assert!(Duration::Concat(
2472            Box::new(Duration::Specific(1, Unit::Day)),
2473            Box::new(Duration::Concat(
2474                Box::new(Duration::Specific(2, Unit::Minute)),
2475                Box::new(Duration::Specific(3, Unit::Year))
2476            ))
2477        )
2478        .is_sub_daily());
2479    }
2480}