sqldatetime/
date.rs

1//! Date implementation.
2
3use 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), // Unreachable
25    (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/// Weekdays in the order of 1..=7 Sun..=Sat for formatting and calculation use
35#[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    /// Converts `usize` to `WeekDay` in the order of 1..=7 to Sunday..=Saturday
48    ///
49    /// # Panics
50    /// Panics if `weekday` is out of range of 1..=7
51    #[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/// Months in the order of 1..=12 January..=December for formatting use
62#[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    /// Converts `usize` to `Month` in the order of 1..=12 to January..=December
80    ///
81    /// # Panics
82    /// Panics if `month` is out of range of 1..=12
83    #[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/// Date represents a valid Gregorian date.
95#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
96#[repr(transparent)]
97pub struct Date(i32);
98
99impl Date {
100    /// The smallest date that can be represented by `Date`, i.e. `0001-01-01`.
101    pub const MIN: Self = unsafe { Date::from_ymd_unchecked(1, 1, 1) };
102
103    /// The largest date that can be represented by `Date`, i.e. `9999-12-31`.
104    pub const MAX: Self = unsafe { Date::from_ymd_unchecked(9999, 12, 31) };
105
106    /// Creates a `Date` from the given year, month, and day.
107    ///
108    /// # Safety
109    /// This function is unsafe because the values are not checked for validity!
110    /// Before using it, check that the values are all correct.
111    #[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    /// Creates a `Date` from the given year, month, and day.
118    #[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    /// Checks if the given year, month, and day fields are valid.
140    #[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    /// Checks the given year, month, and day fields for building Date.
162    #[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    /// Gets the days from Unix Epoch of this `Date`.
184    #[inline(always)]
185    pub const fn days(self) -> i32 {
186        self.0
187    }
188
189    /// Creates a `Date` from the given days from Unix Epoch without checking validity.
190    ///
191    /// # Safety
192    /// This function is unsafe because the day value is not checked for validity!
193    /// Before using it, check that the value is correct.
194    #[inline(always)]
195    pub const unsafe fn from_days_unchecked(days: i32) -> Self {
196        Date(days)
197    }
198
199    /// Creates a `Date` from the given days from Unix Epoch.
200    #[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    /// Extracts `(year, month, day)` from the date.
210    #[inline]
211    pub const fn extract(self) -> (i32, u32, u32) {
212        julian2date(self.0 + UNIX_EPOCH_JULIAN)
213    }
214
215    /// Makes a new `Timestamp` from the current date, hour, minute, second and microsecond.
216    #[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    /// Makes a new `Timestamp` from the current date and time.
225    #[inline(always)]
226    pub const fn and_time(self, time: Time) -> Timestamp {
227        Timestamp::new(self, time)
228    }
229
230    /// Formats `Date` by given format string.
231    #[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    /// Parses `Date` from given string and format.
238    #[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    /// Makes a new `Timestamp` from the current date and 00:00:00.
245    #[inline(always)]
246    pub(crate) const fn and_zero_time(self) -> Timestamp {
247        Timestamp::new(self, Time::ZERO)
248    }
249
250    /// `Date` adds days.
251    #[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    /// `Date` adds months.
299    /// The date will be adjusted.
300    /// The last day of the month is not considered.
301    #[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    /// `Date` adds months.
309    /// The date will be adjusted.
310    /// The last day of the month is considered.
311    #[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    /// `Date` adds `IntervalYM`
327    /// The date will not be adjusted.
328    #[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    /// `Date` adds `IntervalDT`
334    #[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    /// `Date` adds `Time`
340    #[inline]
341    pub const fn add_time(self, time: Time) -> Timestamp {
342        self.and_time(time)
343    }
344
345    /// `Date` subtracts `Date`. Returns the difference in days between two `Date`
346    #[inline]
347    pub const fn sub_date(self, date: Date) -> i32 {
348        self.days() - date.days()
349    }
350
351    ///`Date` subtracts days.
352    #[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    /// `Date` subtracts `Timestamp`
362    #[inline]
363    pub const fn sub_timestamp(self, timestamp: Timestamp) -> IntervalDT {
364        self.and_zero_time().sub_timestamp(timestamp)
365    }
366
367    /// `Date` subtracts `IntervalYM`
368    #[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    /// `Date` subtracts `IntervalDT`
374    #[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    /// `Date` subtracts `Time`
380    #[inline]
381    pub const fn sub_time(self, time: Time) -> Result<Timestamp> {
382        self.and_zero_time().sub_time(time)
383    }
384
385    /// Extract day of week (1..=7 Sunday..=Saturday)
386    #[inline]
387    pub fn day_of_week(self) -> WeekDay {
388        // Add offset
389        let mut date = self.days() + UNIX_EPOCH_DOW as i32 - 1;
390        date %= 7;
391        if date < 0 {
392            date += 7;
393        }
394        // Change to 1..=7 (Sun..=Sat)
395        WeekDay::from(date as usize + 1)
396    }
397
398    /// Get local system date
399    #[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    /// Converts date to ISO year.
406    #[inline]
407    fn date_to_iso_year(self) -> i32 {
408        // Converts Julian date to day-of-week (0..6 == Mon..Sun)
409        #[inline]
410        fn week_day_of_julian(date: i32) -> i32 {
411            let mut date = date;
412            date %= 7;
413            // Cope if division truncates towards zero, as it probably does
414            if date < 0 {
415                date += 7;
416            }
417            date
418        }
419
420        let mut year = self.year().unwrap();
421        // current day
422        let current_julian_day = self.days() + UNIX_EPOCH_JULIAN;
423        // fourth day of current year
424        let mut fourth_julian_day = date2julian(year, 1, 4);
425        // offset to first day of week (Monday)
426        let mut offset_to_monday = week_day_of_julian(fourth_julian_day);
427
428        // We need the first week containing a Thursday, otherwise this day falls
429        // into the previous year for purposes of counting weeks
430        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        // Sometimes the last few days in a year will fall into the first week of
437        // the next year, so check for this
438        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), // Unreachable
461        ];
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), // Unreachable
479        ];
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    /// Gets the last day in month of this `Date`.
487    #[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), // Unreachable
553            (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            // Sets the month and date into the first week.
647            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), // Unreachable
706            (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), // Unreachable
734            (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        // Out of order
864        {
865            // Parse
866
867            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            // Format
881            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        // Duplicate parse
889        {
890            assert!(Date::parse("2021-04-22 thu 5", "yyyy-mm-dd dy d").is_err());
891
892            // todo All types duplication check, including parse and format
893        }
894
895        // Default
896        {
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        // Can not absence of year\month\day
907        {
908            assert!(Date::parse("2022-4", "yyyy-mm-dd").is_err());
909        }
910
911        // Short format
912        {
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        // Normal
939        {
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        // Day parse check
963        {
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        // Duplicate format
1024        {
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        // Invalid
1042        {
1043            // Parse
1044            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        // Out of range
1084        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        // Normal
1095        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        // Out of range
1125        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        // Normal
1133        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        // Leap year
1152        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        // End of the month
1163        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        // Out of range
1195        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        // Normal
1203        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        // Leap year
1222        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        // End of the month
1233        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        // Normal add positive interval test
1282        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        // Normal sub negative interval test
1288        let interval = -IntervalDT::try_from_dhms(1, 2, 3, 4, 5).unwrap();
1289        assert_eq!(date.sub_interval_dt(interval).unwrap(), expect);
1290
1291        // Add positive interval with carry test
1292        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        // Sub negative interval with carry test
1298        let interval = -IntervalDT::try_from_dhms(1, 0, 0, 0, 1).unwrap();
1299        assert_eq!(date.sub_interval_dt(interval).unwrap(), expect);
1300
1301        // Normal add negative interval test
1302        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        // Normal sub positive interval test
1308        let interval = IntervalDT::try_from_dhms(1, 2, 3, 4, 5).unwrap();
1309        assert_eq!(date.sub_interval_dt(interval).unwrap(), expect);
1310
1311        // Add negative interval with carry test
1312        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        // Sub positive interval with carry test
1318        let interval = IntervalDT::try_from_dhms(0, 0, 0, 0, 1).unwrap();
1319        assert_eq!(date.sub_interval_dt(interval).unwrap(), expect);
1320
1321        // Boundary test
1322        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        // Add positive
1348        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        // Sub negative
1362        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        // Sub positive
1376        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        // Add negative
1389        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        // Boundary test
1420        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        // Month day overflow
1428        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        // Out of range
1491        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        // Test ISO Year
1582        // First date of range
1583        assert_eq!(
1584            generate_date(1, 1, 1),
1585            generate_date(1, 1, 1).trunc_iso_year().unwrap()
1586        );
1587        // First year of Julian date
1588        assert_eq!(
1589            generate_date(1583, 1, 3),
1590            generate_date(1583, 12, 31).trunc_iso_year().unwrap()
1591        );
1592        // Last date of range
1593        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        // Previous two years
1599        assert_eq!(
1600            generate_date(2019, 12, 30),
1601            generate_date(2021, 1, 3).trunc_iso_year().unwrap()
1602        );
1603        // Previous one year
1604        assert_eq!(
1605            generate_date(2018, 12, 31),
1606            generate_date(2019, 12, 29).trunc_iso_year().unwrap()
1607        );
1608        // Same year
1609        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        // Test ISO Year
1680        // First date of range
1681        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        // Previous two years
1691        assert_eq!(
1692            generate_date(2019, 12, 30),
1693            generate_date(2021, 1, 3).round_iso_year().unwrap()
1694        );
1695        // Same year
1696        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        // Next year
1713        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}