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)]
10pub enum DateTime {
12 DateTime(DateExpr, Time),
14 TimeDate(Time, DateExpr),
16 After(Duration, Box<DateTime>),
18 Before(Duration, Box<DateTime>),
20 Now,
22}
23
24impl DateTime {
25 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 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 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 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)]
153pub enum DateExpr {
155 Date(Date),
156 DateRelative(Date, RelativeSpecifier, Unit),
158 DateExpressionAfter(Date, Duration),
160 DateExpressionBefore(Date, Duration),
161 UnitRelative(RelativeSpecifier, Unit),
162 RelativeWeekday(RelativeSpecifier, Weekday),
163 WeekdayRelative(Weekday, RelativeSpecifier, Unit),
164 WeekdayExpressionAfter(Weekday, Duration),
166 WeekdayExpressionBefore(Weekday, Duration),
167 Before(Duration, Date),
168 After(Duration, Date),
169 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 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 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 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 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)]
471pub 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 tokens += 1;
540
541 if let Some((num2, t)) = Num::parse(&l[tokens..]) {
542 tokens += t;
543 if l.get(tokens)? == delim {
544 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 == &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 == &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 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 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; 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; 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 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 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 if let Some((triple, t)) = NumTriple::parse(&l[tokens..]) {
1212 tokens += t;
1213
1214 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 } 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 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 } 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 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 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 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 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 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 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 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 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 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 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 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 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 assert!(Date::parse(lexemes.as_slice()).is_none());
2307 }
2308
2309 #[test]
2310 fn test_march_dst_transition() {
2311 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 assert!(res.is_err());
2329 }
2330
2331 #[test]
2332 fn test_november_dst_transition() {
2333 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 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 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}