1use crate::common::{
4 date2julian, days_of_month, is_valid_date, julian2date, DATE_MAX_YEAR, DATE_MIN_YEAR,
5 MONTHS_PER_YEAR, UNIX_EPOCH_JULIAN,
6};
7use crate::error::{Error, Result};
8use crate::format::{Formatter, LazyFormat, NaiveDateTime};
9use crate::local::Local;
10use crate::{DateTime, IntervalDT, IntervalYM, Round, Time, Timestamp, Trunc};
11use std::cmp::{min, Ordering};
12use std::convert::TryFrom;
13use std::fmt::Display;
14
15type DateSubMethod = fn(Date, i32) -> Result<Date>;
16
17pub const UNIX_EPOCH_DOW: WeekDay = WeekDay::Thursday;
18
19const ROUNDS_UP_DAY: u32 = 16;
20
21const ADD_MONTHS_MAX_MONTH: i32 = 9999 * 12 - 1;
22
23const ISO_YEAR_TABLE: [(DateSubMethod, i32); 8] = [
24 (sub_to_date, 0), (sub_to_date, -1),
26 (current_date, 0),
27 (sub_to_date, 1),
28 (sub_to_date, 2),
29 (sub_to_date, 3),
30 (sub_to_date, -3),
31 (sub_to_date, -2),
32];
33
34#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq)]
36pub enum WeekDay {
37 Sunday = 1,
38 Monday = 2,
39 Tuesday = 3,
40 Wednesday = 4,
41 Thursday = 5,
42 Friday = 6,
43 Saturday = 7,
44}
45
46impl From<usize> for WeekDay {
47 #[inline]
52 fn from(weekday: usize) -> Self {
53 use crate::date::WeekDay::*;
54 const WEEKDAY_TABLE: [WeekDay; 7] = [
55 Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday,
56 ];
57 WEEKDAY_TABLE[weekday - 1]
58 }
59}
60
61#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq)]
63pub enum Month {
64 January = 1,
65 February = 2,
66 March = 3,
67 April = 4,
68 May = 5,
69 June = 6,
70 July = 7,
71 August = 8,
72 September = 9,
73 October = 10,
74 November = 11,
75 December = 12,
76}
77
78impl From<usize> for Month {
79 #[inline]
84 fn from(month: usize) -> Self {
85 use crate::date::Month::*;
86 const MONTH_TABLE: [Month; 12] = [
87 January, February, March, April, May, June, July, August, September, October, November,
88 December,
89 ];
90 MONTH_TABLE[month - 1]
91 }
92}
93
94#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
96#[repr(transparent)]
97pub struct Date(i32);
98
99impl Date {
100 pub const MIN: Self = unsafe { Date::from_ymd_unchecked(1, 1, 1) };
102
103 pub const MAX: Self = unsafe { Date::from_ymd_unchecked(9999, 12, 31) };
105
106 #[inline]
112 pub const unsafe fn from_ymd_unchecked(year: i32, month: u32, day: u32) -> Date {
113 let date = date2julian(year, month, day) - UNIX_EPOCH_JULIAN;
114 Date(date)
115 }
116
117 #[inline]
119 pub const fn try_from_ymd(year: i32, month: u32, day: u32) -> Result<Date> {
120 if year < DATE_MIN_YEAR || year > DATE_MAX_YEAR {
121 return Err(Error::DateOutOfRange);
122 }
123
124 if month < 1 || month > MONTHS_PER_YEAR {
125 return Err(Error::InvalidMonth);
126 }
127
128 if day < 1 || day > 31 {
129 return Err(Error::InvalidDay);
130 }
131
132 if day > days_of_month(year, month) {
133 return Err(Error::InvalidDate);
134 }
135
136 Ok(unsafe { Date::from_ymd_unchecked(year, month, day) })
137 }
138
139 #[inline]
141 pub const fn is_valid(year: i32, month: u32, day: u32) -> bool {
142 if year < DATE_MIN_YEAR || year > DATE_MAX_YEAR {
143 return false;
144 }
145
146 if month < 1 || month > MONTHS_PER_YEAR {
147 return false;
148 }
149
150 if day < 1 || day > 31 {
151 return false;
152 }
153
154 if day > days_of_month(year, month) {
155 return false;
156 }
157
158 true
159 }
160
161 #[inline]
163 pub(crate) const fn validate_ymd(year: i32, month: u32, day: u32) -> Result<()> {
164 if year < DATE_MIN_YEAR || year > DATE_MAX_YEAR {
165 return Err(Error::DateOutOfRange);
166 }
167
168 if month < 1 || month > MONTHS_PER_YEAR {
169 return Err(Error::InvalidMonth);
170 }
171
172 if day < 1 || day > 31 {
173 return Err(Error::InvalidDay);
174 }
175
176 if day > days_of_month(year, month) {
177 return Err(Error::InvalidDate);
178 }
179
180 Ok(())
181 }
182
183 #[inline(always)]
185 pub const fn days(self) -> i32 {
186 self.0
187 }
188
189 #[inline(always)]
195 pub const unsafe fn from_days_unchecked(days: i32) -> Self {
196 Date(days)
197 }
198
199 #[inline]
201 pub const fn try_from_days(days: i32) -> Result<Self> {
202 if is_valid_date(days) {
203 Ok(unsafe { Date::from_days_unchecked(days) })
204 } else {
205 Err(Error::DateOutOfRange)
206 }
207 }
208
209 #[inline]
211 pub const fn extract(self) -> (i32, u32, u32) {
212 julian2date(self.0 + UNIX_EPOCH_JULIAN)
213 }
214
215 #[inline]
217 pub fn and_hms(self, hour: u32, minute: u32, sec: u32, usec: u32) -> Result<Timestamp> {
218 Ok(Timestamp::new(
219 self,
220 Time::try_from_hms(hour, minute, sec, usec)?,
221 ))
222 }
223
224 #[inline(always)]
226 pub const fn and_time(self, time: Time) -> Timestamp {
227 Timestamp::new(self, time)
228 }
229
230 #[inline]
232 pub fn format<S: AsRef<str>>(self, fmt: S) -> Result<impl Display> {
233 let fmt = Formatter::try_new(fmt)?;
234 Ok(LazyFormat::new(fmt, self))
235 }
236
237 #[inline]
239 pub fn parse<S1: AsRef<str>, S2: AsRef<str>>(input: S1, fmt: S2) -> Result<Self> {
240 let fmt = Formatter::try_new(fmt)?;
241 fmt.parse(input)
242 }
243
244 #[inline(always)]
246 pub(crate) const fn and_zero_time(self) -> Timestamp {
247 Timestamp::new(self, Time::ZERO)
248 }
249
250 #[inline]
252 pub const fn add_days(self, days: i32) -> Result<Date> {
253 let result = self.days().checked_add(days);
254 match result {
255 Some(d) => Date::try_from_days(d),
256 None => Err(Error::DateOutOfRange),
257 }
258 }
259
260 #[inline]
261 pub(crate) fn add_months_internal<
262 const CHECK_RANGE: bool,
263 const ADJUST_DAY: bool,
264 const CONSIDER_END_OF_MONTH: bool,
265 >(
266 self,
267 months: i32,
268 ) -> Result<(i32, u32, u32)> {
269 if !CHECK_RANGE || (-ADD_MONTHS_MAX_MONTH..=ADD_MONTHS_MAX_MONTH).contains(&months) {
270 let (year, month, day) = self.extract();
271
272 let mut new_month = month as i32 + months;
273 let mut new_year = year;
274
275 if new_month > MONTHS_PER_YEAR as i32 {
276 new_year += (new_month - 1) / MONTHS_PER_YEAR as i32;
277 new_month = (new_month - 1) % MONTHS_PER_YEAR as i32 + 1;
278 } else if new_month < 1 {
279 new_year += new_month / MONTHS_PER_YEAR as i32 - 1;
280 new_month = new_month % MONTHS_PER_YEAR as i32 + MONTHS_PER_YEAR as i32;
281 }
282
283 let new_day = if ADJUST_DAY {
284 if CONSIDER_END_OF_MONTH && day == days_of_month(year, month) {
285 days_of_month(new_year, new_month as u32)
286 } else {
287 min(day, days_of_month(new_year, new_month as u32))
288 }
289 } else {
290 day
291 };
292 Ok((new_year, new_month as u32, new_day))
293 } else {
294 Err(Error::DateOutOfRange)
295 }
296 }
297
298 #[inline]
302 pub fn add_months(self, months: i32) -> Result<Date> {
303 let (new_year, new_month, new_day) =
304 self.add_months_internal::<true, true, false>(months)?;
305 Date::try_from_ymd(new_year, new_month, new_day)
306 }
307
308 #[inline]
312 pub fn add_months2(self, months: i32) -> Result<Date> {
313 let (new_year, new_month, new_day) =
314 self.add_months_internal::<true, true, true>(months)?;
315 Date::try_from_ymd(new_year, new_month, new_day)
316 }
317
318 #[inline]
319 pub(crate) fn add_interval_ym_internal(self, interval: IntervalYM) -> Result<Date> {
320 let (new_year, new_month, day) =
321 self.add_months_internal::<false, false, false>(interval.months())?;
322
323 Date::try_from_ymd(new_year, new_month, day)
324 }
325
326 #[inline]
329 pub fn add_interval_ym(self, interval: IntervalYM) -> Result<Timestamp> {
330 Ok(self.add_interval_ym_internal(interval)?.and_zero_time())
331 }
332
333 #[inline]
335 pub const fn add_interval_dt(self, interval: IntervalDT) -> Result<Timestamp> {
336 self.and_zero_time().add_interval_dt(interval)
337 }
338
339 #[inline]
341 pub const fn add_time(self, time: Time) -> Timestamp {
342 self.and_time(time)
343 }
344
345 #[inline]
347 pub const fn sub_date(self, date: Date) -> i32 {
348 self.days() - date.days()
349 }
350
351 #[inline]
353 pub const fn sub_days(self, days: i32) -> Result<Date> {
354 let result = self.days().checked_sub(days);
355 match result {
356 Some(d) => Date::try_from_days(d),
357 None => Err(Error::DateOutOfRange),
358 }
359 }
360
361 #[inline]
363 pub const fn sub_timestamp(self, timestamp: Timestamp) -> IntervalDT {
364 self.and_zero_time().sub_timestamp(timestamp)
365 }
366
367 #[inline]
369 pub fn sub_interval_ym(self, interval: IntervalYM) -> Result<Timestamp> {
370 Ok(self.add_interval_ym_internal(-interval)?.and_zero_time())
371 }
372
373 #[inline]
375 pub const fn sub_interval_dt(self, interval: IntervalDT) -> Result<Timestamp> {
376 self.and_zero_time().sub_interval_dt(interval)
377 }
378
379 #[inline]
381 pub const fn sub_time(self, time: Time) -> Result<Timestamp> {
382 self.and_zero_time().sub_time(time)
383 }
384
385 #[inline]
387 pub fn day_of_week(self) -> WeekDay {
388 let mut date = self.days() + UNIX_EPOCH_DOW as i32 - 1;
390 date %= 7;
391 if date < 0 {
392 date += 7;
393 }
394 WeekDay::from(date as usize + 1)
396 }
397
398 #[inline]
400 pub fn now() -> Result<Date> {
401 let now = Local::now();
402 Date::try_from_ymd(now.year(), now.month(), now.day())
403 }
404
405 #[inline]
407 fn date_to_iso_year(self) -> i32 {
408 #[inline]
410 fn week_day_of_julian(date: i32) -> i32 {
411 let mut date = date;
412 date %= 7;
413 if date < 0 {
415 date += 7;
416 }
417 date
418 }
419
420 let mut year = self.year().unwrap();
421 let current_julian_day = self.days() + UNIX_EPOCH_JULIAN;
423 let mut fourth_julian_day = date2julian(year, 1, 4);
425 let mut offset_to_monday = week_day_of_julian(fourth_julian_day);
427
428 if current_julian_day < fourth_julian_day - offset_to_monday {
431 fourth_julian_day = date2julian(year - 1, 1, 4);
432 offset_to_monday = week_day_of_julian(fourth_julian_day);
433 year -= 1;
434 }
435
436 let num_of_week = (current_julian_day - (fourth_julian_day - offset_to_monday)) / 7 + 1;
439 if num_of_week >= 52 {
440 fourth_julian_day = date2julian(year + 1, 1, 4);
441 offset_to_monday = week_day_of_julian(fourth_julian_day);
442 if current_julian_day >= fourth_julian_day - offset_to_monday {
443 year += 1;
444 }
445 }
446
447 year
448 }
449
450 #[inline]
451 pub(crate) fn round_week_internal(self, year: i32) -> Result<Date> {
452 const WEEK_TABLE: [(DateSubMethod, i32); 8] = [
453 (current_date, 0),
454 (sub_to_date, 1),
455 (sub_to_date, 2),
456 (sub_to_date, 3),
457 (sub_to_date, -3),
458 (sub_to_date, -2),
459 (sub_to_date, -1),
460 (sub_to_date, 0), ];
462
463 let week_day = self.sub_date(unsafe { Date::from_ymd_unchecked(year, 1, 1) }) % 7;
464 let (to_first_date_of_week, remain_day) = WEEK_TABLE[week_day as usize];
465 to_first_date_of_week(self, remain_day)
466 }
467
468 #[inline]
469 pub(crate) fn round_month_start_week_internal(self, day: i32) -> Result<Date> {
470 const MONTH_START_WEEK_TABLE: [(DateSubMethod, i32); 8] = [
471 (sub_to_date, -1),
472 (current_date, 0),
473 (sub_to_date, 1),
474 (sub_to_date, 2),
475 (sub_to_date, 3),
476 (sub_to_date, -3),
477 (sub_to_date, -2),
478 (sub_to_date, 0), ];
480
481 let week_day = day % 7;
482 let (to_first_date_of_week, remain_day) = MONTH_START_WEEK_TABLE[week_day as usize];
483 to_first_date_of_week(self, remain_day)
484 }
485
486 #[inline]
488 pub fn last_day_of_month(self) -> Date {
489 let (year, month, day) = self.extract();
490
491 let result_day = days_of_month(year, month);
492 let result = self.days() + result_day as i32 - day as i32;
493
494 unsafe { Date::from_days_unchecked(result) }
495 }
496}
497
498impl Trunc for Date {
499 #[inline]
500 fn trunc_century(self) -> Result<Self> {
501 let mut year = self.year().unwrap();
502
503 if year % 100 == 0 {
504 year -= 1;
505 }
506
507 year = year / 100 * 100 + 1;
508 Ok(unsafe { Date::from_ymd_unchecked(year, 1, 1) })
509 }
510
511 #[inline]
512 fn trunc_year(self) -> Result<Self> {
513 Ok(unsafe { Date::from_ymd_unchecked(self.year().unwrap(), 1, 1) })
514 }
515
516 #[inline]
517 fn trunc_iso_year(self) -> Result<Self> {
518 let iso_year = self.date_to_iso_year();
519 let first_date = unsafe { Date::from_ymd_unchecked(iso_year, 1, 1) };
520 let week_day = first_date.day_of_week() as usize;
521 let (to_first_date_of_week, remain_day) = ISO_YEAR_TABLE[week_day];
522 to_first_date_of_week(first_date, remain_day)
523 }
524
525 #[inline]
526 fn trunc_quarter(self) -> Result<Self> {
527 const QUARTER_FIRST_MONTH: [u32; 12] = [1, 1, 1, 4, 4, 4, 7, 7, 7, 10, 10, 10];
528
529 let (year, month, _) = self.extract();
530 let quarter_month = QUARTER_FIRST_MONTH[month as usize - 1];
531
532 Ok(unsafe { Date::from_ymd_unchecked(year, quarter_month, 1) })
533 }
534
535 #[inline]
536 fn trunc_month(self) -> Result<Self> {
537 let (year, month, _) = self.extract();
538 Ok(unsafe { Date::from_ymd_unchecked(year, month, 1) })
539 }
540
541 #[inline]
542 fn trunc_week(self) -> Result<Self> {
543 let trunc_day =
544 self.sub_date(unsafe { Date::from_ymd_unchecked(self.year().unwrap(), 1, 1) }) % 7;
545 let res_date = self.sub_days(trunc_day)?;
546 Ok(res_date)
547 }
548
549 #[inline]
550 fn trunc_iso_week(self) -> Result<Self> {
551 const ISO_WEEK_TABLE: [(DateSubMethod, i32); 8] = [
552 (sub_to_date, 0), (sub_to_date, 6),
554 (current_date, 0),
555 (sub_to_date, 1),
556 (sub_to_date, 2),
557 (sub_to_date, 3),
558 (sub_to_date, 4),
559 (sub_to_date, 5),
560 ];
561
562 let week_day = self.day_of_week() as usize;
563 let (to_first_date_of_week, remain_day) = ISO_WEEK_TABLE[week_day];
564 to_first_date_of_week(self, remain_day)
565 }
566
567 #[inline]
568 fn trunc_month_start_week(self) -> Result<Self> {
569 let remain_day = self.day().unwrap() % 7;
570 let trunc_day = if remain_day == 0 { 6 } else { remain_day - 1 };
571 let res_date = self.sub_days(trunc_day)?;
572 Ok(res_date)
573 }
574
575 #[inline]
576 fn trunc_day(self) -> Result<Self> {
577 Ok(self)
578 }
579
580 #[inline]
581 fn trunc_sunday_start_week(self) -> Result<Self> {
582 let res_date = self.sub_days(self.day_of_week() as i32 - 1)?;
583 Ok(res_date)
584 }
585
586 #[inline]
587 fn trunc_hour(self) -> Result<Self> {
588 Ok(self)
589 }
590
591 #[inline]
592 fn trunc_minute(self) -> Result<Self> {
593 Ok(self)
594 }
595}
596
597#[inline(always)]
598fn current_date(date: Date, _sub_day: i32) -> Result<Date> {
599 Ok(date)
600}
601
602#[inline(always)]
603fn sub_to_date(date: Date, sub_day: i32) -> Result<Date> {
604 date.sub_days(sub_day)
605}
606
607impl Round for Date {
608 #[inline]
609 fn round_century(self) -> Result<Self> {
610 let input_year = self.year().unwrap();
611 if input_year > DATE_MAX_YEAR - 50 {
612 return Err(Error::DateOutOfRange);
613 }
614
615 let mut century = input_year / 100;
616 if input_year % 100 == 0 {
617 century -= 1;
618 } else if input_year % 100 > 50 {
619 century += 1;
620 }
621
622 let res_year = century * 100 + 1;
623 Ok(unsafe { Date::from_ymd_unchecked(res_year, 1, 1) })
624 }
625
626 #[inline]
627 fn round_year(self) -> Result<Self> {
628 let (mut year, month, _) = self.extract();
629 if month >= 7 {
630 if year == DATE_MAX_YEAR {
631 return Err(Error::DateOutOfRange);
632 }
633 year += 1;
634 }
635 Ok(unsafe { Date::from_ymd_unchecked(year, 1, 1) })
636 }
637
638 #[inline]
639 fn round_iso_year(self) -> Result<Self> {
640 let (year, month, _) = self.extract();
641 let mut date = self;
642 if month >= 7 {
643 if year == DATE_MAX_YEAR {
644 return Err(Error::DateOutOfRange);
645 }
646 date = unsafe { Date::from_ymd_unchecked(year + 1, 1, 4) };
648 }
649 date.trunc_iso_year()
650 }
651
652 #[inline]
653 fn round_quarter(self) -> Result<Self> {
654 const QUARTER_ROUND_MONTH: [u32; 12] = [1, 4, 4, 4, 7, 7, 7, 10, 10, 10, 1, 1];
655 const QUARTER_TRUNC_MONTH: [u32; 12] = [1, 1, 4, 4, 4, 7, 7, 7, 10, 10, 10, 1];
656
657 let (mut year, month, day) = self.extract();
658 let is_round = day >= ROUNDS_UP_DAY;
659
660 let index = month as usize - 1;
661 let quarter_month = if is_round {
662 if month >= 11 {
663 year += 1;
664 }
665 QUARTER_ROUND_MONTH[index]
666 } else {
667 if month == 12 {
668 year += 1;
669 }
670 QUARTER_TRUNC_MONTH[index]
671 };
672
673 if year > DATE_MAX_YEAR {
674 return Err(Error::DateOutOfRange);
675 }
676
677 Ok(unsafe { Date::from_ymd_unchecked(year, quarter_month, 1) })
678 }
679
680 #[inline]
681 fn round_month(self) -> Result<Self> {
682 let (mut year, mut month, day) = self.extract();
683 if day >= ROUNDS_UP_DAY {
684 if month == 12 {
685 if year == DATE_MAX_YEAR {
686 return Err(Error::DateOutOfRange);
687 }
688 year += 1;
689 month = 1;
690 } else {
691 month += 1;
692 }
693 }
694 Ok(unsafe { Date::from_ymd_unchecked(year, month, 1) })
695 }
696
697 #[inline]
698 fn round_week(self) -> Result<Self> {
699 self.round_week_internal(self.year().unwrap())
700 }
701
702 #[inline]
703 fn round_iso_week(self) -> Result<Self> {
704 const ISO_WEEK_TABLE: [(DateSubMethod, i32); 8] = [
705 (sub_to_date, 0), (sub_to_date, -1),
707 (current_date, 0),
708 (sub_to_date, 1),
709 (sub_to_date, 2),
710 (sub_to_date, 3),
711 (sub_to_date, -3),
712 (sub_to_date, -2),
713 ];
714
715 let week_day = self.day_of_week() as usize;
716 let (to_first_date_of_week, remain_day) = ISO_WEEK_TABLE[week_day];
717 to_first_date_of_week(self, remain_day)
718 }
719
720 #[inline]
721 fn round_month_start_week(self) -> Result<Self> {
722 self.round_month_start_week_internal(self.day().unwrap())
723 }
724
725 #[inline]
726 fn round_day(self) -> Result<Self> {
727 Ok(self)
728 }
729
730 #[inline]
731 fn round_sunday_start_week(self) -> Result<Self> {
732 const SUNDAY_START_WEEK_TABLE: [(DateSubMethod, i32); 8] = [
733 (sub_to_date, 0), (current_date, 0),
735 (sub_to_date, 1),
736 (sub_to_date, 2),
737 (sub_to_date, 3),
738 (sub_to_date, -3),
739 (sub_to_date, -2),
740 (sub_to_date, -1),
741 ];
742
743 let week_day = self.day_of_week() as usize;
744 let (to_first_date_of_week, remain_day) = SUNDAY_START_WEEK_TABLE[week_day];
745 to_first_date_of_week(self, remain_day)
746 }
747
748 #[inline]
749 fn round_hour(self) -> Result<Self> {
750 Ok(self)
751 }
752
753 #[inline]
754 fn round_minute(self) -> Result<Self> {
755 Ok(self)
756 }
757}
758
759impl From<Date> for NaiveDateTime {
760 #[inline]
761 fn from(date: Date) -> Self {
762 let (year, month, day) = date.extract();
763
764 NaiveDateTime {
765 year,
766 month,
767 day,
768 ..NaiveDateTime::new()
769 }
770 }
771}
772
773impl PartialEq<Timestamp> for Date {
774 #[inline]
775 fn eq(&self, other: &Timestamp) -> bool {
776 self.and_zero_time() == *other
777 }
778}
779
780impl PartialOrd<Timestamp> for Date {
781 #[inline]
782 fn partial_cmp(&self, other: &Timestamp) -> Option<Ordering> {
783 Some(self.and_zero_time().usecs().cmp(&other.usecs()))
784 }
785}
786
787impl TryFrom<&NaiveDateTime> for Date {
788 type Error = Error;
789
790 #[inline]
791 fn try_from(dt: &NaiveDateTime) -> Result<Self> {
792 Date::try_from_ymd(dt.year, dt.month, dt.day)
793 }
794}
795
796impl TryFrom<NaiveDateTime> for Date {
797 type Error = Error;
798
799 #[inline]
800 fn try_from(dt: NaiveDateTime) -> Result<Self> {
801 Date::try_from(&dt)
802 }
803}
804
805impl DateTime for Date {
806 #[inline]
807 fn year(&self) -> Option<i32> {
808 let (year, _, _) = self.extract();
809 Some(year)
810 }
811
812 #[inline]
813 fn month(&self) -> Option<i32> {
814 let (_, month, _) = self.extract();
815 Some(month as i32)
816 }
817
818 #[inline]
819 fn day(&self) -> Option<i32> {
820 let (_, _, day) = self.extract();
821 Some(day as i32)
822 }
823
824 #[inline(always)]
825 fn hour(&self) -> Option<i32> {
826 None
827 }
828
829 #[inline(always)]
830 fn minute(&self) -> Option<i32> {
831 None
832 }
833
834 #[inline(always)]
835 fn second(&self) -> Option<f64> {
836 None
837 }
838
839 #[inline(always)]
840 fn date(&self) -> Option<Date> {
841 Some(*self)
842 }
843}
844
845#[cfg(test)]
846mod tests {
847 use super::*;
848
849 #[test]
850 fn test_date() {
851 let date = Date::try_from_ymd(1970, 1, 1).unwrap();
852 assert_eq!(date.days(), 0);
853 assert_eq!(date.extract(), (1970, 1, 1));
854
855 let date = Date::try_from_ymd(1, 1, 1).unwrap();
856 assert_eq!(date.extract(), (1, 1, 1));
857
858 let date = Date::try_from_ymd(9999, 12, 31).unwrap();
859 assert_eq!(date.extract(), (9999, 12, 31));
860 let date2 = Date::parse("9999-12-31", "YYYY-MM-DD").unwrap();
861 assert_eq!(date2, date);
862
863 {
865 let date = Date::try_from_ymd(9999, 12, 31).unwrap();
868 let date2 = Date::parse("9999\\12-31", "yyyy\\mm-dd").unwrap();
869 assert_eq!(date2, date);
870
871 let date2 = Date::parse("9999-. 12--31", "YYYY-. MM--DD").unwrap();
872 assert_eq!(date2, date);
873
874 let date2 = Date::parse("31 9999-. 12", "dd YYYY-. MM").unwrap();
875 assert_eq!(date, date2);
876
877 let date2 = Date::parse("-12 31 -9999;", "-MM DD -yyyy;").unwrap();
878 assert_eq!(date, date2);
879
880 let fmt = date.format("\\YYYY\\ MM-/DD").unwrap();
882 assert_eq!(format!("{}", fmt), "\\9999\\ 12-/31");
883
884 let fmt = date.format("\\YYYY\\ MM-/DD;").unwrap();
885 assert_eq!(format!("{}", fmt), "\\9999\\ 12-/31;");
886 }
887
888 {
890 assert!(Date::parse("2021-04-22 thu 5", "yyyy-mm-dd dy d").is_err());
891
892 }
894
895 {
897 let now = Local::now();
898 let dt = Date::try_from_ymd(now.year(), now.month(), 1).unwrap();
899 let date = Date::parse(" ", " ").unwrap();
900 assert_eq!(date, dt);
901
902 let date = Date::parse("", "").unwrap();
903 assert_eq!(date, dt);
904 }
905
906 {
908 assert!(Date::parse("2022-4", "yyyy-mm-dd").is_err());
909 }
910
911 {
913 let date = generate_date(1234, 8, 6);
914 assert_eq!(format!("{}", date.format("YYYY").unwrap()), "1234");
915 assert_eq!(format!("{}", date.format("DD").unwrap()), "06");
916 assert_eq!(format!("{}", date.format("MON").unwrap()), "AUG");
917 assert_eq!(format!("{}", date.format("Mon").unwrap()), "Aug");
918 assert_eq!(format!("{}", date.format("mon").unwrap()), "aug");
919 assert_eq!(format!("{}", date.format("MONTH").unwrap()), "AUGUST");
920 assert_eq!(format!("{}", date.format("MONtH").unwrap()), "AUGUST");
921 assert_eq!(format!("{}", date.format("Month").unwrap()), "August");
922 assert_eq!(format!("{}", date.format("month").unwrap()), "august");
923 assert_eq!(format!("{}", date.format("WW").unwrap()), "32");
924 assert_eq!(format!("{}", date.format("W").unwrap()), "1");
925 assert_eq!(format!("{}", date.format("DAY").unwrap()), "SUNDAY");
926 assert_eq!(format!("{}", date.format("DAy").unwrap()), "SUNDAY");
927 assert_eq!(format!("{}", date.format("Day").unwrap()), "Sunday");
928 assert_eq!(format!("{}", date.format("DaY").unwrap()), "Sunday");
929 assert_eq!(format!("{}", date.format("day").unwrap()), "sunday");
930 assert_eq!(format!("{}", date.format("daY").unwrap()), "sunday");
931 assert_eq!(format!("{}", date.format("DY").unwrap()), "SUN");
932 assert_eq!(format!("{}", date.format("Dy").unwrap()), "Sun");
933 assert_eq!(format!("{}", date.format("dy").unwrap()), "sun");
934 assert_eq!(format!("{}", date.format("D").unwrap()), "1");
935 assert_eq!(format!("{}", date.format("DDD").unwrap()), "218");
936 }
937
938 {
940 let date = generate_date(2000, 1, 1);
941 let fmt = format!("{}", date.format("yyyy-MONTH-dd").unwrap());
942 assert_eq!(fmt, "2000-JANUARY-01");
943
944 let date = generate_date(2000, 1, 1);
945 let fmt = format!("{}", date.format("yyyy-Mon-dd").unwrap());
946 assert_eq!(fmt, "2000-Jan-01");
947
948 let fmt = format!("{}", date.format("Day yyyy-Mon-dd").unwrap());
949 assert_eq!(fmt, "Saturday 2000-Jan-01");
950
951 let fmt = format!("{}", date.format("yyyyMMdd").unwrap());
952 assert_eq!(fmt, "20000101");
953
954 let date = generate_date(2001, 1, 2);
955 assert_eq!(format!("{}", date.format("YYYYMMDD").unwrap()), "20010102");
956
957 assert_eq!(date, Date::parse("20010102", "YYYYMMDD").unwrap());
958
959 assert_eq!(date, Date::parse("2001012", "YYYYMMDD").unwrap());
960 }
961
962 {
964 let date = generate_date(2021, 4, 22);
965 let date2 = Date::parse("2021-04-22 thu", "yyyy-mm-dd dy").unwrap();
966 let date3 = Date::parse("2021-04-22 5", "yyyy-mm-dd d").unwrap();
967 assert_eq!(date, date2);
968 assert_eq!(date, date3);
969
970 let date = generate_date(2022, 6, 21);
971 let date2 = Date::parse("2022 172", "yyyy ddd").unwrap();
972 let date3 = Date::parse("2022-6-21 172", "yyyy-mm-dd ddd").unwrap();
973 assert_eq!(date, date2);
974 assert_eq!(date, date3);
975
976 let date = generate_date(2022, 1, 2);
977 let date2 = Date::parse("2022 2", "yyyy ddd").unwrap();
978 assert_eq!(date, date2);
979
980 let date = generate_date(2022, 1, 30);
981 let date2 = Date::parse("2022 30", "yyyy ddd").unwrap();
982 assert_eq!(date, date2);
983
984 let date = generate_date(2022, 1, 31);
985 let date2 = Date::parse("2022 31", "yyyy ddd").unwrap();
986 assert_eq!(date, date2);
987
988 let date = generate_date(2022, 3, 1);
989 let date2 = Date::parse("2022 60", "yyyy ddd").unwrap();
990 assert_eq!(date, date2);
991
992 let date = generate_date(2022, 8, 22);
993 let date2 = Date::parse("2022 234", "yyyy ddd").unwrap();
994 assert_eq!(date, date2);
995
996 let date = generate_date(2022, 9, 30);
997 let date2 = Date::parse("2022 273", "yyyy ddd").unwrap();
998 assert_eq!(date, date2);
999
1000 let date = generate_date(2022, 12, 2);
1001 let date2 = Date::parse("2022 336", "yyyy ddd").unwrap();
1002 assert_eq!(date, date2);
1003
1004 let date = generate_date(2022, 12, 31);
1005 let date2 = Date::parse("2022 365", "yyyy ddd").unwrap();
1006 assert_eq!(date, date2);
1007
1008 assert!(Date::parse("-172", "ddd").is_err());
1009 assert!(Date::parse("0", "ddd").is_err());
1010 assert!(Date::parse("672", "ddd").is_err());
1011
1012 assert!(Date::parse("2022-6-20 172", "yyyy-mm-dd ddd").is_err());
1013
1014 assert!(Date::parse("2021-04-23 thur", "yyyy-mm-dd dy").is_err());
1015
1016 assert!(Date::parse("2021-04-27 tues", "yyyy-mm-dd dy").is_err());
1017
1018 assert!(Date::parse("2021-04-23 5", "yyyy-mm-dd d").is_err());
1019
1020 assert!(Date::parse("2021-04-22 ", "yyyy-mm-dd d",).is_err());
1021 }
1022
1023 {
1025 let date = generate_date(2021, 4, 25);
1026 assert_eq!(
1027 format!(
1028 "{}",
1029 date.format("DAY DaY DY D W WW WW MM MM yyyy YYYY DDD")
1030 .unwrap()
1031 ),
1032 "SUNDAY Sunday SUN 1 4 17 17 04 04 2021 2021 115"
1033 );
1034
1035 assert_eq!(
1036 format!("{}", date.format("DAYDaYDYDWWWWWDMMMMyyyyYYYYDDD").unwrap()),
1037 "SUNDAYSundaySUN1171741040420212021115"
1038 );
1039 }
1040
1041 {
1043 assert!(Date::parse("2021-04-22", "yyyy-mmX-dd").is_err());
1045 assert!(Date::parse("2021-04-22", "yyy-mm-dd").is_err());
1046 assert!(Date::parse("2021-04-32", "yyyy-mm-dd").is_err());
1047 assert!(Date::parse("10000-04-30", "yyyy-mm-dd").is_err());
1048 assert!(Date::parse("2021-04-22", "ABCD-mm-dd").is_err());
1049 assert!(Date::parse("2021423", "yyyymmdd").is_err());
1050 assert!(Date::parse("2021-04-22 11", "yyyy-mm-dd hh").is_err());
1051 assert!(Date::parse("2021-04-22 11", "yyyy-mm-dd mi").is_err());
1052 assert!(Date::parse("2021-04-22 11", "yyyy-mm-dd ss").is_err());
1053 assert!(Date::parse("2021-04-22 11", "yyyy-mm-dd ff").is_err());
1054 assert!(Date::parse("2021-04-25 4", "yyyy-mm-dd w").is_err());
1055 assert!(Date::parse("2021-04-25 17", "yyyy-mm-dd ww").is_err());
1056 }
1057 }
1058
1059 fn generate_ts(
1060 year: i32,
1061 month: u32,
1062 day: u32,
1063 hour: u32,
1064 min: u32,
1065 sec: u32,
1066 usec: u32,
1067 ) -> Timestamp {
1068 Timestamp::new(
1069 Date::try_from_ymd(year, month, day).unwrap(),
1070 Time::try_from_hms(hour, min, sec, usec).unwrap(),
1071 )
1072 }
1073
1074 fn generate_date(year: i32, month: u32, day: u32) -> Date {
1075 Date::try_from_ymd(year, month, day).unwrap()
1076 }
1077
1078 #[test]
1079 fn test_add_sub_days() {
1080 let upper_date = Date::try_from_ymd(9999, 12, 31).unwrap();
1081 let lower_date = Date::try_from_ymd(1, 1, 1).unwrap();
1082
1083 assert!(lower_date.add_days(i32::MAX).is_err());
1085 assert!(lower_date.add_days(234253258).is_err());
1086 assert!(upper_date.add_days(1).is_err());
1087 assert!(upper_date.add_days(i32::MIN).is_err());
1088
1089 assert!(lower_date.sub_days(1).is_err());
1090 assert!(upper_date.sub_days(234253258).is_err());
1091 assert!(lower_date.sub_days(i32::MAX).is_err());
1092 assert!(upper_date.sub_days(i32::MIN).is_err());
1093
1094 assert_eq!(upper_date.sub_days(0).unwrap(), upper_date);
1096 assert_eq!(upper_date.add_days(0).unwrap(), upper_date);
1097 assert_eq!(
1098 upper_date.sub_days(366).unwrap(),
1099 Date::try_from_ymd(9998, 12, 30).unwrap()
1100 );
1101 assert_eq!(
1102 lower_date.add_days(366).unwrap(),
1103 Date::try_from_ymd(2, 1, 2).unwrap()
1104 );
1105
1106 let date = Date::try_from_ymd(5000, 6, 15).unwrap();
1107 assert_eq!(
1108 date.add_days(718).unwrap(),
1109 Date::try_from_ymd(5002, 6, 3).unwrap()
1110 );
1111 assert_eq!(
1112 date.sub_days(718).unwrap(),
1113 Date::try_from_ymd(4998, 6, 27).unwrap()
1114 );
1115 assert_eq!(date.sub_days(718).unwrap(), date.add_days(-718).unwrap());
1116 assert_eq!(date.sub_days(-718).unwrap(), date.add_days(718).unwrap());
1117 }
1118
1119 #[test]
1120 fn test_add_months() {
1121 let upper_date = Date::try_from_ymd(9999, 12, 31).unwrap();
1122 let lower_date = Date::try_from_ymd(1, 1, 1).unwrap();
1123
1124 assert!(lower_date.add_months(i32::MAX).is_err());
1126 assert!(lower_date.add_months(234253258).is_err());
1127 assert!(lower_date.add_months(9999 * 12).is_err());
1128 assert!(upper_date.add_months(1).is_err());
1129 assert!(upper_date.add_months(i32::MIN).is_err());
1130 assert!(upper_date.add_months(-(9999 * 12)).is_err());
1131
1132 assert_eq!(upper_date.add_months(0).unwrap(), upper_date);
1134 assert_eq!(
1135 upper_date.add_months(-13).unwrap(),
1136 Date::try_from_ymd(9998, 11, 30).unwrap()
1137 );
1138 assert_eq!(
1139 upper_date.add_months(-(9999 * 12 - 1)).unwrap(),
1140 Date::try_from_ymd(1, 1, 31).unwrap()
1141 );
1142 assert_eq!(
1143 lower_date.add_months(13).unwrap(),
1144 Date::try_from_ymd(2, 2, 1).unwrap()
1145 );
1146 assert_eq!(
1147 lower_date.add_months(9999 * 12 - 1).unwrap(),
1148 Date::try_from_ymd(9999, 12, 1).unwrap()
1149 );
1150
1151 let date = Date::try_from_ymd(5000, 1, 31).unwrap();
1153 assert_eq!(
1154 date.add_months(49).unwrap(),
1155 Date::try_from_ymd(5004, 2, 29).unwrap()
1156 );
1157 assert_eq!(
1158 date.add_months(-23).unwrap(),
1159 Date::try_from_ymd(4998, 2, 28).unwrap()
1160 );
1161
1162 let date = Date::try_from_ymd(5000, 4, 30).unwrap();
1164 assert_eq!(
1165 date.add_months(1).unwrap(),
1166 Date::try_from_ymd(5000, 5, 30).unwrap()
1167 );
1168 let date = Date::try_from_ymd(5000, 2, 28).unwrap();
1169 assert_eq!(
1170 date.add_months(48).unwrap(),
1171 Date::try_from_ymd(5004, 2, 28).unwrap()
1172 );
1173 let date = Date::try_from_ymd(5000, 3, 29).unwrap();
1174 assert_eq!(
1175 date.add_months(-1).unwrap(),
1176 Date::try_from_ymd(5000, 2, 28).unwrap()
1177 );
1178
1179 let date = generate_date(2000, 2, 29);
1180 assert_eq!(date.add_months(24).unwrap(), generate_date(2002, 2, 28));
1181
1182 let date = generate_date(2001, 2, 28);
1183 assert_eq!(date.add_months(1).unwrap(), generate_date(2001, 3, 28));
1184
1185 let date = generate_date(2001, 2, 28);
1186 assert_eq!(date.add_months(36).unwrap(), generate_date(2004, 2, 28));
1187 }
1188
1189 #[test]
1190 fn test_add_months2() {
1191 let upper_date = Date::try_from_ymd(9999, 12, 31).unwrap();
1192 let lower_date = Date::try_from_ymd(1, 1, 1).unwrap();
1193
1194 assert!(lower_date.add_months2(i32::MAX).is_err());
1196 assert!(lower_date.add_months2(234253258).is_err());
1197 assert!(lower_date.add_months2(9999 * 12).is_err());
1198 assert!(upper_date.add_months2(1).is_err());
1199 assert!(upper_date.add_months2(i32::MIN).is_err());
1200 assert!(upper_date.add_months2(-(9999 * 12)).is_err());
1201
1202 assert_eq!(upper_date.add_months2(0).unwrap(), upper_date);
1204 assert_eq!(
1205 upper_date.add_months2(-13).unwrap(),
1206 Date::try_from_ymd(9998, 11, 30).unwrap()
1207 );
1208 assert_eq!(
1209 upper_date.add_months2(-(9999 * 12 - 1)).unwrap(),
1210 Date::try_from_ymd(1, 1, 31).unwrap()
1211 );
1212 assert_eq!(
1213 lower_date.add_months2(13).unwrap(),
1214 Date::try_from_ymd(2, 2, 1).unwrap()
1215 );
1216 assert_eq!(
1217 lower_date.add_months2(9999 * 12 - 1).unwrap(),
1218 Date::try_from_ymd(9999, 12, 1).unwrap()
1219 );
1220
1221 let date = Date::try_from_ymd(5000, 1, 31).unwrap();
1223 assert_eq!(
1224 date.add_months2(49).unwrap(),
1225 Date::try_from_ymd(5004, 2, 29).unwrap()
1226 );
1227 assert_eq!(
1228 date.add_months2(-23).unwrap(),
1229 Date::try_from_ymd(4998, 2, 28).unwrap()
1230 );
1231
1232 let date = Date::try_from_ymd(5000, 4, 30).unwrap();
1234 assert_eq!(
1235 date.add_months2(1).unwrap(),
1236 Date::try_from_ymd(5000, 5, 31).unwrap()
1237 );
1238 let date = Date::try_from_ymd(5000, 2, 28).unwrap();
1239 assert_eq!(
1240 date.add_months2(48).unwrap(),
1241 Date::try_from_ymd(5004, 2, 29).unwrap()
1242 );
1243 let date = Date::try_from_ymd(5000, 3, 29).unwrap();
1244 assert_eq!(
1245 date.add_months2(-1).unwrap(),
1246 Date::try_from_ymd(5000, 2, 28).unwrap()
1247 );
1248
1249 let date = generate_date(2000, 2, 29);
1250 assert_eq!(date.add_months2(24).unwrap(), generate_date(2002, 2, 28));
1251
1252 let date = generate_date(2001, 2, 28);
1253 assert_eq!(date.add_months2(1).unwrap(), generate_date(2001, 3, 31));
1254
1255 let date = generate_date(2001, 2, 28);
1256 assert_eq!(date.add_months2(36).unwrap(), generate_date(2004, 2, 29));
1257 }
1258
1259 #[test]
1260 fn test_and_time() {
1261 assert_eq!(
1262 Date::try_from_ymd(9999, 12, 31)
1263 .unwrap()
1264 .and_time(Time::try_from_hms(23, 59, 59, 999999).unwrap()),
1265 generate_ts(9999, 12, 31, 23, 59, 59, 999999)
1266 );
1267
1268 assert_eq!(
1269 Date::try_from_ymd(1, 1, 1).unwrap().and_zero_time(),
1270 generate_ts(1, 1, 1, 0, 0, 0, 0)
1271 );
1272
1273 assert!(Date::try_from_ymd(1, 1, 1)
1274 .unwrap()
1275 .and_hms(25, 6, 6, 7)
1276 .is_err());
1277 }
1278
1279 #[test]
1280 fn test_date_add_sub_interval_dt() {
1281 let date = generate_date(2001, 3, 31);
1283 let interval = IntervalDT::try_from_dhms(1, 2, 3, 4, 5).unwrap();
1284 let expect = generate_ts(2001, 4, 1, 2, 3, 4, 5);
1285 assert_eq!(date.add_interval_dt(interval).unwrap(), expect);
1286
1287 let interval = -IntervalDT::try_from_dhms(1, 2, 3, 4, 5).unwrap();
1289 assert_eq!(date.sub_interval_dt(interval).unwrap(), expect);
1290
1291 let date = generate_date(2001, 12, 31);
1293 let interval = IntervalDT::try_from_dhms(1, 0, 0, 0, 1).unwrap();
1294 let expect = generate_ts(2002, 1, 1, 0, 0, 0, 1);
1295 assert_eq!(date.add_interval_dt(interval).unwrap(), expect);
1296
1297 let interval = -IntervalDT::try_from_dhms(1, 0, 0, 0, 1).unwrap();
1299 assert_eq!(date.sub_interval_dt(interval).unwrap(), expect);
1300
1301 let date = generate_date(2001, 3, 31);
1303 let interval = -IntervalDT::try_from_dhms(1, 2, 3, 4, 5).unwrap();
1304 let expect = generate_ts(2001, 3, 29, 21, 56, 55, 999995);
1305 assert_eq!(date.add_interval_dt(interval).unwrap(), expect);
1306
1307 let interval = IntervalDT::try_from_dhms(1, 2, 3, 4, 5).unwrap();
1309 assert_eq!(date.sub_interval_dt(interval).unwrap(), expect);
1310
1311 let date = generate_date(1970, 1, 1);
1313 let interval = -IntervalDT::try_from_dhms(0, 0, 0, 0, 1).unwrap();
1314 let expect = generate_ts(1969, 12, 31, 23, 59, 59, 999999);
1315 assert_eq!(date.add_interval_dt(interval).unwrap(), expect);
1316
1317 let interval = IntervalDT::try_from_dhms(0, 0, 0, 0, 1).unwrap();
1319 assert_eq!(date.sub_interval_dt(interval).unwrap(), expect);
1320
1321 let date = generate_date(9999, 12, 31);
1323 let interval = IntervalDT::try_from_dhms(5, 4, 3, 2, 1).unwrap();
1324 let expect = generate_ts(9999, 12, 25, 19, 56, 57, 999999);
1325 assert_eq!(date.sub_interval_dt(interval).unwrap(), expect);
1326
1327 let interval = IntervalDT::try_from_dhms(1, 0, 0, 0, 1).unwrap();
1328 assert!(date.add_interval_dt(interval).is_err());
1329
1330 let interval = IntervalDT::try_from_dhms(12345, 12, 3, 5, 6).unwrap();
1331 assert!(date.add_interval_dt(interval).is_err());
1332
1333 let date = generate_date(1, 1, 1);
1334 let interval = IntervalDT::try_from_dhms(5, 4, 3, 2, 1).unwrap();
1335 let expect = generate_ts(1, 1, 6, 4, 3, 2, 1);
1336 assert_eq!(date.add_interval_dt(interval).unwrap(), expect);
1337
1338 let interval = IntervalDT::try_from_dhms(0, 0, 0, 0, 1).unwrap();
1339 assert!(date.sub_interval_dt(interval).is_err());
1340
1341 let interval = IntervalDT::try_from_dhms(12345, 12, 3, 5, 6).unwrap();
1342 assert!(date.sub_interval_dt(interval).is_err());
1343 }
1344
1345 #[test]
1346 fn test_date_add_sub_interval_ym() {
1347 let date = generate_date(2001, 3, 31);
1349 let interval = IntervalYM::try_from_ym(0, 2).unwrap();
1350 assert_eq!(
1351 date.add_interval_ym(interval).unwrap(),
1352 generate_ts(2001, 5, 31, 0, 0, 0, 0)
1353 );
1354
1355 let interval = IntervalYM::try_from_ym(1, 2).unwrap();
1356 assert_eq!(
1357 date.add_interval_ym(interval).unwrap(),
1358 generate_ts(2002, 5, 31, 0, 0, 0, 0)
1359 );
1360
1361 let date = generate_date(2001, 3, 31);
1363 let interval = IntervalYM::try_from_ym(0, 2).unwrap();
1364 assert_eq!(
1365 date.sub_interval_ym(-interval).unwrap(),
1366 generate_ts(2001, 5, 31, 0, 0, 0, 0)
1367 );
1368
1369 let interval = IntervalYM::try_from_ym(1, 2).unwrap();
1370 assert_eq!(
1371 date.sub_interval_ym(-interval).unwrap(),
1372 generate_ts(2002, 5, 31, 0, 0, 0, 0)
1373 );
1374
1375 let interval = IntervalYM::try_from_ym(0, 2).unwrap();
1377 assert_eq!(
1378 date.sub_interval_ym(interval).unwrap(),
1379 generate_ts(2001, 1, 31, 0, 0, 0, 0)
1380 );
1381
1382 let interval = IntervalYM::try_from_ym(1, 2).unwrap();
1383 assert_eq!(
1384 date.sub_interval_ym(interval).unwrap(),
1385 generate_ts(2000, 1, 31, 0, 0, 0, 0)
1386 );
1387
1388 let interval = IntervalYM::try_from_ym(0, 2).unwrap();
1390 assert_eq!(
1391 date.add_interval_ym(-interval).unwrap(),
1392 generate_ts(2001, 1, 31, 0, 0, 0, 0)
1393 );
1394
1395 let interval = IntervalYM::try_from_ym(1, 2).unwrap();
1396 assert_eq!(
1397 date.add_interval_ym(-interval).unwrap(),
1398 generate_ts(2000, 1, 31, 0, 0, 0, 0)
1399 );
1400
1401 let date = generate_date(2001, 2, 28);
1402 let interval = IntervalYM::try_from_ym(2, 0).unwrap();
1403 assert_eq!(
1404 date.add_interval_ym(interval).unwrap(),
1405 generate_ts(2003, 2, 28, 0, 0, 0, 0)
1406 );
1407
1408 let interval = IntervalYM::try_from_ym(2, 1).unwrap();
1409 assert_eq!(
1410 date.add_interval_ym(interval).unwrap(),
1411 generate_ts(2003, 3, 28, 0, 0, 0, 0)
1412 );
1413
1414 assert_eq!(
1415 date.sub_interval_ym(interval).unwrap(),
1416 generate_ts(1999, 1, 28, 0, 0, 0, 0)
1417 );
1418
1419 let upper_date = generate_date(9999, 12, 31);
1421 let lower_date = generate_date(1, 1, 1);
1422 let interval = IntervalYM::try_from_ym(0, 1).unwrap();
1423
1424 assert!(upper_date.add_interval_ym(interval).is_err());
1425 assert!(lower_date.sub_interval_ym(interval).is_err());
1426
1427 let date = generate_date(2001, 3, 31);
1429 let interval = IntervalYM::try_from_ym(1, 1).unwrap();
1430 assert!(date.add_interval_ym(interval).is_err());
1431
1432 let interval = IntervalYM::try_from_ym(0, 11).unwrap();
1433 assert!(date.add_interval_ym(interval).is_err());
1434
1435 let interval = IntervalYM::try_from_ym(2, 11).unwrap();
1436 assert!(date.add_interval_ym(interval).is_err());
1437
1438 let interval = IntervalYM::try_from_ym(1, 1).unwrap();
1439 assert!(date.sub_interval_ym(-interval).is_err());
1440
1441 let interval = IntervalYM::try_from_ym(0, 11).unwrap();
1442 assert!(date.sub_interval_ym(-interval).is_err());
1443
1444 let interval = IntervalYM::try_from_ym(2, 11).unwrap();
1445 assert!(date.sub_interval_ym(-interval).is_err());
1446
1447 let interval = IntervalYM::try_from_ym(1, 1).unwrap();
1448 assert!(date.sub_interval_ym(interval).is_err());
1449
1450 let interval = IntervalYM::try_from_ym(0, 11).unwrap();
1451 assert!(date.sub_interval_ym(interval).is_err());
1452
1453 let interval = IntervalYM::try_from_ym(2, 1).unwrap();
1454 assert!(date.sub_interval_ym(interval).is_err());
1455
1456 let interval = IntervalYM::try_from_ym(2, 1).unwrap();
1457 assert!(date.sub_interval_ym(interval).is_err());
1458
1459 let interval = IntervalYM::try_from_ym(1, 1).unwrap();
1460 assert!(date.add_interval_ym(-interval).is_err());
1461
1462 let interval = IntervalYM::try_from_ym(0, 11).unwrap();
1463 assert!(date.add_interval_ym(-interval).is_err());
1464
1465 let interval = IntervalYM::try_from_ym(2, 1).unwrap();
1466 assert!(date.add_interval_ym(-interval).is_err());
1467
1468 let date = generate_date(2000, 2, 29);
1469 let interval = IntervalYM::try_from_ym(2, 0).unwrap();
1470 assert!(date.add_interval_ym(interval).is_err());
1471 }
1472
1473 #[test]
1474 fn test_add_sub_time() {
1475 assert_eq!(
1476 Date::try_from_ymd(9999, 12, 31)
1477 .unwrap()
1478 .add_time(Time::try_from_hms(12, 34, 56, 999999).unwrap()),
1479 generate_ts(9999, 12, 31, 12, 34, 56, 999999)
1480 );
1481
1482 assert_eq!(
1483 Date::try_from_ymd(9999, 12, 31)
1484 .unwrap()
1485 .sub_time(Time::try_from_hms(12, 34, 56, 999999).unwrap())
1486 .unwrap(),
1487 generate_ts(9999, 12, 30, 11, 25, 3, 1)
1488 );
1489
1490 assert!(Date::try_from_ymd(1, 1, 1)
1492 .unwrap()
1493 .sub_time(Time::try_from_hms(12, 34, 56, 999999).unwrap())
1494 .is_err());
1495 }
1496
1497 #[test]
1498 fn test_date_sub_timestamp() {
1499 let upper_date = generate_date(9999, 12, 31);
1500 let lower_date = generate_date(1, 1, 1);
1501 let upper_ts = generate_ts(9999, 12, 31, 23, 59, 59, 999999);
1502 let lower_ts = generate_ts(1, 1, 1, 0, 0, 0, 0);
1503 let ts = generate_ts(5000, 6, 15, 12, 30, 30, 500000);
1504
1505 assert_eq!(
1506 upper_date.sub_timestamp(lower_ts),
1507 IntervalDT::try_from_dhms(3652058, 0, 0, 0, 0).unwrap()
1508 );
1509
1510 assert_eq!(
1511 upper_date.sub_timestamp(ts),
1512 IntervalDT::try_from_dhms(1826045, 11, 29, 29, 500000).unwrap()
1513 );
1514
1515 assert_eq!(
1516 lower_date.sub_timestamp(upper_ts),
1517 -IntervalDT::try_from_dhms(3652058, 23, 59, 59, 999999).unwrap()
1518 );
1519 }
1520
1521 #[test]
1522 fn test_date_sub_date() {
1523 let upper_date = generate_date(9999, 12, 31);
1524 let lower_date = generate_date(1, 1, 1);
1525 let date = generate_date(5000, 6, 15);
1526
1527 assert_eq!(upper_date.sub_date(lower_date), 3652058);
1528
1529 assert_eq!(lower_date.sub_date(upper_date), -3652058);
1530
1531 assert_eq!(upper_date.sub_date(date), 1826046);
1532 }
1533
1534 #[test]
1535 fn test_date_cmp_timestamp() {
1536 let ts = generate_ts(1970, 1, 1, 1, 1, 1, 1);
1537 let date = generate_date(1970, 1, 1);
1538 assert!(date < ts);
1539 let ts = generate_ts(1970, 1, 1, 0, 0, 0, 0);
1540 assert!(date == ts);
1541 }
1542
1543 fn test_extract(year: i32, month: u32, day: u32) {
1544 let date = generate_date(year, month, day);
1545 assert_eq!(year, date.year().unwrap());
1546 assert_eq!(month as i32, date.month().unwrap());
1547 assert_eq!(day as i32, date.day().unwrap());
1548
1549 assert!(date.hour().is_none());
1550 assert!(date.minute().is_none());
1551 assert!(date.second().is_none());
1552 }
1553
1554 #[test]
1555 fn test_date_extract() {
1556 test_extract(1960, 12, 31);
1557 test_extract(1, 1, 1);
1558 test_extract(1969, 12, 31);
1559 test_extract(1969, 12, 30);
1560 test_extract(1970, 1, 1);
1561 test_extract(1999, 10, 21);
1562 test_extract(9999, 12, 31);
1563 }
1564
1565 #[test]
1566 fn test_now() {
1567 let now = Local::now();
1568 let dt = Date::now().unwrap();
1569 assert_eq!(now.year(), dt.year().unwrap());
1570 assert_eq!(now.month() as i32, dt.month().unwrap());
1571 assert_eq!(now.day() as i32, dt.day().unwrap());
1572 }
1573
1574 #[test]
1575 fn test_trunc() {
1576 let dt = generate_date(1996, 10, 24);
1577
1578 assert_eq!(generate_date(1901, 1, 1), dt.trunc_century().unwrap());
1579 assert_eq!(generate_date(1996, 1, 1), dt.trunc_year().unwrap());
1580
1581 assert_eq!(
1584 generate_date(1, 1, 1),
1585 generate_date(1, 1, 1).trunc_iso_year().unwrap()
1586 );
1587 assert_eq!(
1589 generate_date(1583, 1, 3),
1590 generate_date(1583, 12, 31).trunc_iso_year().unwrap()
1591 );
1592 assert_eq!(
1594 generate_date(9999, 1, 4),
1595 generate_date(9999, 12, 31).trunc_iso_year().unwrap()
1596 );
1597 assert_eq!(generate_date(1996, 1, 1), dt.trunc_iso_year().unwrap());
1598 assert_eq!(
1600 generate_date(2019, 12, 30),
1601 generate_date(2021, 1, 3).trunc_iso_year().unwrap()
1602 );
1603 assert_eq!(
1605 generate_date(2018, 12, 31),
1606 generate_date(2019, 12, 29).trunc_iso_year().unwrap()
1607 );
1608 assert_eq!(
1610 generate_date(2019, 12, 30),
1611 generate_date(2019, 12, 31).trunc_iso_year().unwrap()
1612 );
1613 assert_eq!(
1614 generate_date(2018, 12, 31),
1615 generate_date(2018, 12, 31).trunc_iso_year().unwrap()
1616 );
1617
1618 assert_eq!(generate_date(1996, 10, 1), dt.trunc_quarter().unwrap());
1619 assert_eq!(generate_date(1996, 10, 1), dt.trunc_month().unwrap());
1620 assert_eq!(generate_date(1996, 10, 21), dt.trunc_week().unwrap());
1621 assert_eq!(generate_date(1996, 10, 21), dt.trunc_iso_week().unwrap());
1622 assert_eq!(
1623 generate_date(1996, 10, 22),
1624 dt.trunc_month_start_week().unwrap()
1625 );
1626 assert_eq!(
1627 generate_date(1996, 10, 1),
1628 generate_date(1996, 10, 7).trunc_month_start_week().unwrap()
1629 );
1630 assert_eq!(generate_date(1996, 10, 24), dt.trunc_day().unwrap());
1631 assert_eq!(
1632 generate_date(1996, 10, 20),
1633 dt.trunc_sunday_start_week().unwrap()
1634 );
1635 assert_eq!(
1636 generate_date(2015, 4, 11),
1637 generate_date(2015, 4, 11).trunc_hour().unwrap()
1638 );
1639 assert_eq!(
1640 generate_date(2015, 4, 11),
1641 generate_date(2015, 4, 11).trunc_minute().unwrap()
1642 );
1643 }
1644
1645 #[test]
1646 fn test_round_overflow() {
1647 let dt_max = generate_date(DATE_MAX_YEAR, 12, 31);
1648
1649 let dt1 = generate_date(9951, 1, 1);
1650 assert!(dt1.round_century().is_err());
1651 assert!(dt_max.round_century().is_err());
1652
1653 let dt1 = generate_date(DATE_MAX_YEAR, 7, 1);
1654 assert!(dt1.round_year().is_err());
1655 assert!(dt_max.round_year().is_err());
1656
1657 let dt1 = generate_date(DATE_MAX_YEAR, 11, 16);
1658 let dt2 = generate_date(DATE_MAX_YEAR, 12, 1);
1659 let dt3 = generate_date(DATE_MAX_YEAR, 12, 16);
1660 assert!(dt1.round_quarter().is_err());
1661 assert!(dt2.round_quarter().is_err());
1662 assert!(dt3.round_quarter().is_err());
1663 assert!(dt_max.round_quarter().is_err());
1664
1665 let dt1 = generate_date(DATE_MAX_YEAR, 12, 16);
1666 assert!(dt1.round_month().is_err());
1667 assert!(dt_max.round_month().is_err());
1668
1669 assert!(dt_max.round_sunday_start_week().is_err());
1670 }
1671
1672 #[test]
1673 fn test_round() {
1674 let dt = generate_date(1996, 10, 24);
1675
1676 assert_eq!(generate_date(2001, 1, 1), dt.round_century().unwrap());
1677 assert_eq!(generate_date(1997, 1, 1), dt.round_year().unwrap());
1678
1679 assert_eq!(
1682 generate_date(1, 1, 1),
1683 generate_date(1, 1, 1).round_iso_year().unwrap()
1684 );
1685 assert_eq!(
1686 generate_date(1584, 1, 2),
1687 generate_date(1583, 12, 31).round_iso_year().unwrap()
1688 );
1689 assert_eq!(generate_date(1996, 12, 30), dt.round_iso_year().unwrap());
1690 assert_eq!(
1692 generate_date(2019, 12, 30),
1693 generate_date(2021, 1, 3).round_iso_year().unwrap()
1694 );
1695 assert_eq!(
1697 generate_date(2019, 12, 30),
1698 generate_date(2019, 12, 29).round_iso_year().unwrap()
1699 );
1700 assert_eq!(
1701 generate_date(2019, 12, 30),
1702 generate_date(2019, 12, 31).round_iso_year().unwrap()
1703 );
1704 assert_eq!(
1705 generate_date(2018, 12, 31),
1706 generate_date(2018, 12, 30).round_iso_year().unwrap()
1707 );
1708 assert_eq!(
1709 generate_date(2018, 12, 31),
1710 generate_date(2018, 12, 31).round_iso_year().unwrap()
1711 );
1712 assert_eq!(
1714 generate_date(2001, 1, 1),
1715 generate_date(2000, 12, 30).round_iso_year().unwrap()
1716 );
1717 assert_eq!(
1718 generate_date(2001, 1, 1),
1719 generate_date(2000, 12, 31).round_iso_year().unwrap()
1720 );
1721
1722 assert_eq!(generate_date(1996, 10, 1), dt.round_quarter().unwrap());
1723 assert_eq!(
1724 generate_date(2022, 1, 1),
1725 generate_date(2021, 11, 16).round_quarter().unwrap()
1726 );
1727 assert_eq!(
1728 generate_date(2022, 1, 1),
1729 generate_date(2021, 12, 16).round_quarter().unwrap()
1730 );
1731 assert_eq!(
1732 generate_date(2022, 1, 1),
1733 generate_date(2021, 12, 30).round_quarter().unwrap()
1734 );
1735 assert_eq!(
1736 generate_date(9999, 4, 1),
1737 generate_date(9999, 2, 28).round_quarter().unwrap()
1738 );
1739 assert_eq!(
1740 generate_date(9999, 7, 1),
1741 generate_date(9999, 5, 28).round_quarter().unwrap()
1742 );
1743 assert_eq!(generate_date(1996, 11, 1), dt.round_month().unwrap());
1744 assert_eq!(
1745 generate_date(2021, 10, 15),
1746 generate_date(2021, 10, 13).round_week().unwrap()
1747 );
1748 assert_eq!(
1749 generate_date(2021, 10, 18),
1750 generate_date(2021, 10, 15).round_iso_week().unwrap()
1751 );
1752 assert_eq!(
1753 generate_date(2021, 11, 8),
1754 generate_date(2021, 11, 5).round_month_start_week().unwrap()
1755 );
1756 assert_eq!(
1757 generate_date(1996, 10, 24),
1758 generate_date(1996, 10, 24).round_day().unwrap()
1759 );
1760 assert_eq!(
1761 generate_date(1996, 10, 27),
1762 dt.round_sunday_start_week().unwrap()
1763 );
1764 assert_eq!(
1765 generate_date(2015, 3, 3),
1766 generate_date(2015, 3, 3).round_hour().unwrap()
1767 );
1768 assert_eq!(
1769 generate_date(2015, 3, 3),
1770 generate_date(2015, 3, 3).round_hour().unwrap()
1771 );
1772 assert_eq!(
1773 generate_date(2015, 3, 3),
1774 generate_date(2015, 3, 3).round_minute().unwrap()
1775 );
1776 assert_eq!(
1777 generate_date(2015, 3, 3),
1778 generate_date(2015, 3, 3).round_minute().unwrap()
1779 );
1780 }
1781
1782 #[test]
1783 fn test_last_day_of_month() {
1784 assert_eq!(
1785 generate_date(2021, 9, 23).last_day_of_month(),
1786 generate_date(2021, 9, 30)
1787 );
1788 assert_eq!(
1789 generate_date(1970, 1, 1).last_day_of_month(),
1790 generate_date(1970, 1, 31)
1791 );
1792 assert_eq!(
1793 generate_date(1704, 2, 1).last_day_of_month(),
1794 generate_date(1704, 2, 29)
1795 );
1796 assert_eq!(
1797 generate_date(1705, 2, 10).last_day_of_month(),
1798 generate_date(1705, 2, 28)
1799 );
1800 assert_eq!(
1801 generate_date(1, 1, 1).last_day_of_month(),
1802 generate_date(1, 1, 31)
1803 );
1804 assert_eq!(
1805 generate_date(9999, 12, 31).last_day_of_month(),
1806 generate_date(9999, 12, 31)
1807 );
1808 }
1809}