Skip to main content

jiff/civil/
date.rs

1use core::time::Duration as UnsignedDuration;
2
3use crate::{
4    civil::{DateTime, Era, ISOWeekDate, Time, Weekday},
5    duration::{Duration, SDuration},
6    error::{civil::Error as E, unit::UnitConfigError, Error, ErrorContext},
7    fmt::{
8        self,
9        temporal::{DEFAULT_DATETIME_PARSER, DEFAULT_DATETIME_PRINTER},
10    },
11    shared::util::itime::{self, IDate, IEpochDay},
12    tz::TimeZone,
13    util::{b, constant},
14    RoundMode, SignedDuration, Span, SpanRound, Unit, Zoned,
15};
16
17/// A representation of a civil date in the Gregorian calendar.
18///
19/// A `Date` value corresponds to a triple of year, month and day. Every `Date`
20/// value is guaranteed to be a valid Gregorian calendar date. For example,
21/// both `2023-02-29` and `2023-11-31` are invalid and cannot be represented by
22/// a `Date`.
23///
24/// # Civil dates
25///
26/// A `Date` value behaves without regard to daylight saving time or time
27/// zones in general. When doing arithmetic on dates with spans defined in
28/// units of time (such as with [`Date::checked_add`]), days are considered to
29/// always be precisely `86,400` seconds long.
30///
31/// # Parsing and printing
32///
33/// The `Date` type provides convenient trait implementations of
34/// [`std::str::FromStr`] and [`std::fmt::Display`]:
35///
36/// ```
37/// use jiff::civil::Date;
38///
39/// let date: Date = "2024-06-19".parse()?;
40/// assert_eq!(date.to_string(), "2024-06-19");
41///
42/// # Ok::<(), Box<dyn std::error::Error>>(())
43/// ```
44///
45/// A civil `Date` can also be parsed from something that _contains_ a date,
46/// but with perhaps other data (such as an offset or time zone):
47///
48/// ```
49/// use jiff::civil::Date;
50///
51/// let date: Date = "2024-06-19T15:22:45-04[America/New_York]".parse()?;
52/// assert_eq!(date.to_string(), "2024-06-19");
53///
54/// # Ok::<(), Box<dyn std::error::Error>>(())
55/// ```
56///
57/// For more information on the specific format supported, see the
58/// [`fmt::temporal`](crate::fmt::temporal) module documentation.
59///
60/// # Default value
61///
62/// For convenience, this type implements the `Default` trait. Its default
63/// value corresponds to `0000-01-01`. One can also access this value via the
64/// `Date::ZERO` constant.
65///
66/// # Comparisons
67///
68/// The `Date` type provides both `Eq` and `Ord` trait implementations to
69/// facilitate easy comparisons. When a date `d1` occurs before a date `d2`,
70/// then `d1 < d2`. For example:
71///
72/// ```
73/// use jiff::civil::date;
74///
75/// let d1 = date(2024, 3, 11);
76/// let d2 = date(2025, 1, 31);
77/// assert!(d1 < d2);
78/// ```
79///
80/// # Arithmetic
81///
82/// This type provides routines for adding and subtracting spans of time, as
83/// well as computing the span of time between two `Date` values.
84///
85/// For adding or subtracting spans of time, one can use any of the following
86/// routines:
87///
88/// * [`Date::checked_add`] or [`Date::checked_sub`] for checked arithmetic.
89/// * [`Date::saturating_add`] or [`Date::saturating_sub`] for saturating
90/// arithmetic.
91///
92/// Additionally, checked arithmetic is available via the `Add` and `Sub`
93/// trait implementations. When the result overflows, a panic occurs.
94///
95/// ```
96/// use jiff::{civil::date, ToSpan};
97///
98/// let start = date(2024, 2, 25);
99/// let one_week_later = start + 1.weeks();
100/// assert_eq!(one_week_later, date(2024, 3, 3));
101/// ```
102///
103/// One can compute the span of time between two dates using either
104/// [`Date::until`] or [`Date::since`]. It's also possible to subtract two
105/// `Date` values directly via a `Sub` trait implementation:
106///
107/// ```
108/// use jiff::{civil::date, ToSpan};
109///
110/// let date1 = date(2024, 3, 3);
111/// let date2 = date(2024, 2, 25);
112/// assert_eq!(date1 - date2, 7.days().fieldwise());
113/// ```
114///
115/// The `until` and `since` APIs are polymorphic and allow re-balancing and
116/// rounding the span returned. For example, the default largest unit is days
117/// (as exemplified above), but we can ask for bigger units:
118///
119/// ```
120/// use jiff::{civil::date, ToSpan, Unit};
121///
122/// let date1 = date(2024, 5, 3);
123/// let date2 = date(2024, 2, 25);
124/// assert_eq!(
125///     date1.since((Unit::Year, date2))?,
126///     2.months().days(7).fieldwise(),
127/// );
128///
129/// # Ok::<(), Box<dyn std::error::Error>>(())
130/// ```
131///
132/// Or even round the span returned:
133///
134/// ```
135/// use jiff::{civil::{DateDifference, date}, RoundMode, ToSpan, Unit};
136///
137/// let date1 = date(2024, 5, 15);
138/// let date2 = date(2024, 2, 25);
139/// assert_eq!(
140///     date1.since(
141///         DateDifference::new(date2)
142///             .smallest(Unit::Month)
143///             .largest(Unit::Year),
144///     )?,
145///     2.months().fieldwise(),
146/// );
147/// // `DateDifference` uses truncation as a rounding mode by default,
148/// // but you can set the rounding mode to break ties away from zero:
149/// assert_eq!(
150///     date1.since(
151///         DateDifference::new(date2)
152///             .smallest(Unit::Month)
153///             .largest(Unit::Year)
154///             .mode(RoundMode::HalfExpand),
155///     )?,
156///     // Rounds up to 8 days.
157///     3.months().fieldwise(),
158/// );
159///
160/// # Ok::<(), Box<dyn std::error::Error>>(())
161/// ```
162///
163/// # Rounding
164///
165/// Rounding dates is currently not supported. If you want this functionality,
166/// please participate in the [issue tracking its support][add-date-rounding].
167///
168/// [add-date-rounding]: https://github.com/BurntSushi/jiff/issues/1
169#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
170pub struct Date {
171    year: i16,
172    month: i8,
173    day: i8,
174}
175
176impl Date {
177    /// The minimum representable Gregorian date.
178    ///
179    /// The minimum is chosen such that any [`Timestamp`](crate::Timestamp)
180    /// combined with any valid time zone offset can be infallibly converted to
181    /// this type. This means that the minimum `Timestamp` is guaranteed to be
182    /// bigger than the minimum `Date`.
183    pub const MIN: Date = Date::constant(-9999, 1, 1);
184
185    /// The maximum representable Gregorian date.
186    ///
187    /// The maximum is chosen such that any [`Timestamp`](crate::Timestamp)
188    /// combined with any valid time zone offset can be infallibly converted to
189    /// this type. This means that the maximum `Timestamp` is guaranteed to be
190    /// smaller than the maximum `Date`.
191    pub const MAX: Date = Date::constant(9999, 12, 31);
192
193    /// The first day of the zeroth year.
194    ///
195    /// This is guaranteed to be equivalent to `Date::default()`.
196    ///
197    /// # Example
198    ///
199    /// ```
200    /// use jiff::civil::Date;
201    ///
202    /// assert_eq!(Date::ZERO, Date::default());
203    /// ```
204    pub const ZERO: Date = Date::constant(0, 1, 1);
205
206    /// Creates a new `Date` value from its component year, month and day
207    /// values.
208    ///
209    /// To set the component values of a date after creating it, use
210    /// [`DateWith`] via [`Date::with`] to build a new [`Date`] from the fields
211    /// of an existing date.
212    ///
213    /// # Errors
214    ///
215    /// This returns an error when the given year-month-day does not
216    /// correspond to a valid date. Namely, all of the following must be
217    /// true:
218    ///
219    /// * The year must be in the range `-9999..=9999`.
220    /// * The month must be in the range `1..=12`.
221    /// * The day must be at least `1` and must be at most the number of days
222    /// in the corresponding month. So for example, `2024-02-29` is valid but
223    /// `2023-02-29` is not.
224    ///
225    /// # Example
226    ///
227    /// This shows an example of a valid date:
228    ///
229    /// ```
230    /// use jiff::civil::Date;
231    ///
232    /// let d = Date::new(2024, 2, 29).unwrap();
233    /// assert_eq!(d.year(), 2024);
234    /// assert_eq!(d.month(), 2);
235    /// assert_eq!(d.day(), 29);
236    /// ```
237    ///
238    /// This shows an example of an invalid date:
239    ///
240    /// ```
241    /// use jiff::civil::Date;
242    ///
243    /// assert!(Date::new(2023, 2, 29).is_err());
244    /// ```
245    #[inline]
246    pub fn new(year: i16, month: i8, day: i8) -> Result<Date, Error> {
247        let year = b::Year::check(year)?;
248        let month = b::Month::check(month)?;
249        if day > 28 && day > itime::days_in_month(year, month) {
250            return Err(Error::itime_range(
251                crate::shared::util::itime::RangeError::DateInvalidDays {
252                    year,
253                    month,
254                },
255            ));
256        }
257        Ok(Date::new_unchecked(year, month, day))
258    }
259
260    /// Like `Date::new`, but constrains the day value to the last day of
261    /// `month`.
262    ///
263    /// This still returns an error when `day < 1` or when `year` or `month`
264    /// are invalid.
265    #[inline]
266    fn new_constrain(year: i16, month: i8, day: i8) -> Result<Date, Error> {
267        let year = b::Year::check(year)?;
268        let month = b::Month::check(month)?;
269        let day = if day < 1 {
270            return Err(b::Day::error().into());
271        } else if day > 28 {
272            day.min(itime::days_in_month(year, month))
273        } else {
274            day
275        };
276        Ok(Date::new_unchecked(year, month, day))
277    }
278
279    /// Like `Date::new`, but does not checking on the values given when
280    /// `debug_assertions` aren't enabled.
281    ///
282    /// This is useful in contexts where the values are known to be valid.
283    ///
284    /// NOTE: It's important that this is not made public without careful
285    /// consideration. In particular, if it's public, it probably shouldn't
286    /// be safe to call so that callers can rely on the ranges of methods
287    /// like `Date::{year,month,day}`.
288    #[inline]
289    const fn new_unchecked(year: i16, month: i8, day: i8) -> Date {
290        debug_assert!(b::Year::checkc(year as i64).is_ok());
291        debug_assert!(b::Month::checkc(month as i64).is_ok());
292        debug_assert!(b::Day::checkc(day as i64).is_ok());
293        debug_assert!(day <= itime::days_in_month(year, month));
294        Date { year, month, day }
295    }
296
297    /// Creates a new `Date` value in a `const` context.
298    ///
299    /// # Panics
300    ///
301    /// This routine panics when [`Date::new`] would return an error. That is,
302    /// when the given year-month-day does not correspond to a valid date.
303    /// Namely, all of the following must be true:
304    ///
305    /// * The year must be in the range `-9999..=9999`.
306    /// * The month must be in the range `1..=12`.
307    /// * The day must be at least `1` and must be at most the number of days
308    /// in the corresponding month. So for example, `2024-02-29` is valid but
309    /// `2023-02-29` is not.
310    ///
311    /// # Example
312    ///
313    /// ```
314    /// use jiff::civil::Date;
315    ///
316    /// let d = Date::constant(2024, 2, 29);
317    /// assert_eq!(d.year(), 2024);
318    /// assert_eq!(d.month(), 2);
319    /// assert_eq!(d.day(), 29);
320    /// ```
321    #[inline]
322    pub const fn constant(year: i16, month: i8, day: i8) -> Date {
323        let year =
324            constant::unwrapr!(b::Year::checkc(year as i64), "invalid year");
325        let month = constant::unwrapr!(
326            b::Month::checkc(month as i64),
327            "invalid month"
328        );
329        if day > itime::days_in_month(year, month) {
330            panic!("invalid month/day combination");
331        }
332        Date::new_unchecked(year, month, day)
333    }
334
335    /// Construct a Gregorian date from an [ISO 8601 week date].
336    ///
337    /// The [`ISOWeekDate`] type describes itself in more detail, but in
338    /// brief, the ISO week date calendar system eschews months in favor of
339    /// weeks.
340    ///
341    /// The minimum and maximum values of an `ISOWeekDate` correspond
342    /// precisely to the minimum and maximum values of a `Date`. Therefore,
343    /// converting between them is lossless and infallible.
344    ///
345    /// This routine is equivalent to [`ISOWeekDate::date`]. It is also
346    /// available via a `From<ISOWeekDate>` trait implementation for `Date`.
347    ///
348    /// [ISO 8601 week date]: https://en.wikipedia.org/wiki/ISO_week_date
349    ///
350    /// # Example
351    ///
352    /// This shows a number of examples demonstrating the conversion from an
353    /// ISO 8601 week date to a Gregorian date.
354    ///
355    /// ```
356    /// use jiff::civil::{Date, ISOWeekDate, Weekday, date};
357    ///
358    /// let weekdate = ISOWeekDate::new(1994, 52, Weekday::Sunday).unwrap();
359    /// let d = Date::from_iso_week_date(weekdate);
360    /// assert_eq!(d, date(1995, 1, 1));
361    ///
362    /// let weekdate = ISOWeekDate::new(1997, 1, Weekday::Tuesday).unwrap();
363    /// let d = Date::from_iso_week_date(weekdate);
364    /// assert_eq!(d, date(1996, 12, 31));
365    ///
366    /// let weekdate = ISOWeekDate::new(2020, 1, Weekday::Monday).unwrap();
367    /// let d = Date::from_iso_week_date(weekdate);
368    /// assert_eq!(d, date(2019, 12, 30));
369    ///
370    /// let weekdate = ISOWeekDate::new(2024, 10, Weekday::Saturday).unwrap();
371    /// let d = Date::from_iso_week_date(weekdate);
372    /// assert_eq!(d, date(2024, 3, 9));
373    ///
374    /// let weekdate = ISOWeekDate::new(9999, 52, Weekday::Friday).unwrap();
375    /// let d = Date::from_iso_week_date(weekdate);
376    /// assert_eq!(d, date(9999, 12, 31));
377    /// ```
378    #[inline]
379    pub fn from_iso_week_date(weekdate: ISOWeekDate) -> Date {
380        let mut days = iso_week_start_from_year(weekdate.year());
381        let week = i32::from(weekdate.week());
382        let weekday = i32::from(weekdate.weekday().to_monday_zero_offset());
383
384        days += (week - 1) * 7;
385        days += weekday;
386        Date::from_unix_epoch_day(days)
387    }
388
389    /// Create a builder for constructing a `Date` from the fields of this
390    /// date.
391    ///
392    /// See the methods on [`DateWith`] for the different ways one can set the
393    /// fields of a new `Date`.
394    ///
395    /// # Example
396    ///
397    /// The builder ensures one can chain together the individual components
398    /// of a date without it failing at an intermediate step. For example,
399    /// if you had a date of `2024-10-31` and wanted to change both the day
400    /// and the month, and each setting was validated independent of the other,
401    /// you would need to be careful to set the day first and then the month.
402    /// In some cases, you would need to set the month first and then the day!
403    ///
404    /// But with the builder, you can set values in any order:
405    ///
406    /// ```
407    /// use jiff::civil::date;
408    ///
409    /// let d1 = date(2024, 10, 31);
410    /// let d2 = d1.with().month(11).day(30).build()?;
411    /// assert_eq!(d2, date(2024, 11, 30));
412    ///
413    /// let d1 = date(2024, 4, 30);
414    /// let d2 = d1.with().day(31).month(7).build()?;
415    /// assert_eq!(d2, date(2024, 7, 31));
416    ///
417    /// # Ok::<(), Box<dyn std::error::Error>>(())
418    /// ```
419    #[inline]
420    pub fn with(self) -> DateWith {
421        DateWith::new(self)
422    }
423
424    /// Returns the year for this date.
425    ///
426    /// The value returned is guaranteed to be in the range `-9999..=9999`.
427    ///
428    /// # Example
429    ///
430    /// ```
431    /// use jiff::civil::date;
432    ///
433    /// let d1 = date(2024, 3, 9);
434    /// assert_eq!(d1.year(), 2024);
435    ///
436    /// let d2 = date(-2024, 3, 9);
437    /// assert_eq!(d2.year(), -2024);
438    ///
439    /// let d3 = date(0, 3, 9);
440    /// assert_eq!(d3.year(), 0);
441    /// ```
442    #[inline]
443    pub fn year(self) -> i16 {
444        self.year
445    }
446
447    /// Returns the year and its era.
448    ///
449    /// This crate specifically allows years to be negative or `0`, where as
450    /// years written for the Gregorian calendar are always positive and
451    /// greater than `0`. In the Gregorian calendar, the era labels `BCE` and
452    /// `CE` are used to disambiguate between years less than or equal to `0`
453    /// and years greater than `0`, respectively.
454    ///
455    /// The crate is designed this way so that years in the latest era (that
456    /// is, `CE`) are aligned with years in this crate.
457    ///
458    /// The year returned is guaranteed to be in the range `1..=10000`.
459    ///
460    /// # Example
461    ///
462    /// ```
463    /// use jiff::civil::{Era, date};
464    ///
465    /// let d = date(2024, 10, 3);
466    /// assert_eq!(d.era_year(), (2024, Era::CE));
467    ///
468    /// let d = date(1, 10, 3);
469    /// assert_eq!(d.era_year(), (1, Era::CE));
470    ///
471    /// let d = date(0, 10, 3);
472    /// assert_eq!(d.era_year(), (1, Era::BCE));
473    ///
474    /// let d = date(-1, 10, 3);
475    /// assert_eq!(d.era_year(), (2, Era::BCE));
476    ///
477    /// let d = date(-10, 10, 3);
478    /// assert_eq!(d.era_year(), (11, Era::BCE));
479    ///
480    /// let d = date(-9_999, 10, 3);
481    /// assert_eq!(d.era_year(), (10_000, Era::BCE));
482    /// ```
483    #[inline]
484    pub fn era_year(self) -> (i16, Era) {
485        let year = self.year();
486        if year >= 1 {
487            (year, Era::CE)
488        } else {
489            // We specifically ensure our min/max bounds on `Year` always leave
490            // room in its representation to add or subtract 1, so this will
491            // never fail.
492            let era_year = -year + 1;
493            (era_year, Era::BCE)
494        }
495    }
496
497    /// Returns the month for this date.
498    ///
499    /// The value returned is guaranteed to be in the range `1..=12`.
500    ///
501    /// # Example
502    ///
503    /// ```
504    /// use jiff::civil::date;
505    ///
506    /// let d1 = date(2024, 3, 9);
507    /// assert_eq!(d1.month(), 3);
508    /// ```
509    #[inline]
510    pub fn month(self) -> i8 {
511        self.month
512    }
513
514    /// Returns the day for this date.
515    ///
516    /// The value returned is guaranteed to be in the range `1..=31`.
517    ///
518    /// # Example
519    ///
520    /// ```
521    /// use jiff::civil::date;
522    ///
523    /// let d1 = date(2024, 2, 29);
524    /// assert_eq!(d1.day(), 29);
525    /// ```
526    #[inline]
527    pub fn day(self) -> i8 {
528        self.day
529    }
530
531    /// Returns the weekday corresponding to this date.
532    ///
533    /// # Example
534    ///
535    /// ```
536    /// use jiff::civil::{Weekday, date};
537    ///
538    /// // The Unix epoch was on a Thursday.
539    /// let d1 = date(1970, 1, 1);
540    /// assert_eq!(d1.weekday(), Weekday::Thursday);
541    /// // One can also get the weekday as an offset in a variety of schemes.
542    /// assert_eq!(d1.weekday().to_monday_zero_offset(), 3);
543    /// assert_eq!(d1.weekday().to_monday_one_offset(), 4);
544    /// assert_eq!(d1.weekday().to_sunday_zero_offset(), 4);
545    /// assert_eq!(d1.weekday().to_sunday_one_offset(), 5);
546    /// ```
547    #[inline]
548    pub fn weekday(self) -> Weekday {
549        Weekday::from_iweekday(self.to_idate_const().weekday())
550    }
551
552    /// Returns the ordinal day of the year that this date resides in.
553    ///
554    /// For leap years, this always returns a value in the range `1..=366`.
555    /// Otherwise, the value is in the range `1..=365`.
556    ///
557    /// # Example
558    ///
559    /// ```
560    /// use jiff::civil::date;
561    ///
562    /// let d = date(2006, 8, 24);
563    /// assert_eq!(d.day_of_year(), 236);
564    ///
565    /// let d = date(2023, 12, 31);
566    /// assert_eq!(d.day_of_year(), 365);
567    ///
568    /// let d = date(2024, 12, 31);
569    /// assert_eq!(d.day_of_year(), 366);
570    /// ```
571    #[inline]
572    pub fn day_of_year(self) -> i16 {
573        static DAYS_BY_MONTH_NO_LEAP: [i16; 14] =
574            [0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];
575        static DAYS_BY_MONTH_LEAP: [i16; 14] =
576            [0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366];
577        static TABLES: [[i16; 14]; 2] =
578            [DAYS_BY_MONTH_NO_LEAP, DAYS_BY_MONTH_LEAP];
579        TABLES[self.in_leap_year() as usize][self.month() as usize]
580            + i16::from(self.day())
581    }
582
583    /// Returns the ordinal day of the year that this date resides in, but
584    /// ignores leap years.
585    ///
586    /// That is, the range of possible values returned by this routine is
587    /// `1..=365`, even if this date resides in a leap year. If this date is
588    /// February 29, then this routine returns `None`.
589    ///
590    /// The value `365` always corresponds to the last day in the year,
591    /// December 31, even for leap years.
592    ///
593    /// # Example
594    ///
595    /// ```
596    /// use jiff::civil::date;
597    ///
598    /// let d = date(2006, 8, 24);
599    /// assert_eq!(d.day_of_year_no_leap(), Some(236));
600    ///
601    /// let d = date(2023, 12, 31);
602    /// assert_eq!(d.day_of_year_no_leap(), Some(365));
603    ///
604    /// let d = date(2024, 12, 31);
605    /// assert_eq!(d.day_of_year_no_leap(), Some(365));
606    ///
607    /// let d = date(2024, 2, 29);
608    /// assert_eq!(d.day_of_year_no_leap(), None);
609    /// ```
610    #[inline]
611    pub fn day_of_year_no_leap(self) -> Option<i16> {
612        let mut days = self.day_of_year();
613        if self.in_leap_year() {
614            // day=60 is Feb 29
615            if days == 60 {
616                return None;
617            } else if days > 60 {
618                days -= 1;
619            }
620        }
621        Some(days)
622    }
623
624    /// Returns the first date of the month that this date resides in.
625    ///
626    /// # Example
627    ///
628    /// ```
629    /// use jiff::civil::date;
630    ///
631    /// let d = date(2024, 2, 29);
632    /// assert_eq!(d.first_of_month(), date(2024, 2, 1));
633    /// ```
634    #[inline]
635    pub fn first_of_month(self) -> Date {
636        // OK because the first day of the month is always valid.
637        Date::new_unchecked(self.year(), self.month(), 1)
638    }
639
640    /// Returns the last date of the month that this date resides in.
641    ///
642    /// # Example
643    ///
644    /// ```
645    /// use jiff::civil::date;
646    ///
647    /// let d = date(2024, 2, 5);
648    /// assert_eq!(d.last_of_month(), date(2024, 2, 29));
649    /// ```
650    #[inline]
651    pub fn last_of_month(self) -> Date {
652        // OK because the last day of the month is always valid.
653        Date::new_unchecked(self.year(), self.month(), self.days_in_month())
654    }
655
656    /// Returns the total number of days in the the month in which this date
657    /// resides.
658    ///
659    /// This is guaranteed to always return one of the following values,
660    /// depending on the year and the month: 28, 29, 30 or 31.
661    ///
662    /// # Example
663    ///
664    /// ```
665    /// use jiff::civil::date;
666    ///
667    /// let d = date(2024, 2, 10);
668    /// assert_eq!(d.days_in_month(), 29);
669    ///
670    /// let d = date(2023, 2, 10);
671    /// assert_eq!(d.days_in_month(), 28);
672    ///
673    /// let d = date(2024, 8, 15);
674    /// assert_eq!(d.days_in_month(), 31);
675    /// ```
676    #[inline]
677    pub fn days_in_month(self) -> i8 {
678        itime::days_in_month(self.year(), self.month())
679    }
680
681    /// Returns the first date of the year that this date resides in.
682    ///
683    /// # Example
684    ///
685    /// ```
686    /// use jiff::civil::date;
687    ///
688    /// let d = date(2024, 2, 29);
689    /// assert_eq!(d.first_of_year(), date(2024, 1, 1));
690    /// ```
691    #[inline]
692    pub fn first_of_year(self) -> Date {
693        // OK because Jan 1 for all years is valid.
694        Date::new_unchecked(self.year(), 1, 1)
695    }
696
697    /// Returns the last date of the year that this date resides in.
698    ///
699    /// # Example
700    ///
701    /// ```
702    /// use jiff::civil::date;
703    ///
704    /// let d = date(2024, 2, 5);
705    /// assert_eq!(d.last_of_year(), date(2024, 12, 31));
706    /// ```
707    #[inline]
708    pub fn last_of_year(self) -> Date {
709        // OK because Dec 31 for all years is valid.
710        Date::new_unchecked(self.year(), 12, 31)
711    }
712
713    /// Returns the total number of days in the the year in which this date
714    /// resides.
715    ///
716    /// This is guaranteed to always return either `365` or `366`.
717    ///
718    /// # Example
719    ///
720    /// ```
721    /// use jiff::civil::date;
722    ///
723    /// let d = date(2024, 7, 10);
724    /// assert_eq!(d.days_in_year(), 366);
725    ///
726    /// let d = date(2023, 7, 10);
727    /// assert_eq!(d.days_in_year(), 365);
728    /// ```
729    #[inline]
730    pub fn days_in_year(self) -> i16 {
731        if self.in_leap_year() {
732            366
733        } else {
734            365
735        }
736    }
737
738    /// Returns true if and only if the year in which this date resides is a
739    /// leap year.
740    ///
741    /// # Example
742    ///
743    /// ```
744    /// use jiff::civil::date;
745    ///
746    /// assert!(date(2024, 1, 1).in_leap_year());
747    /// assert!(!date(2023, 12, 31).in_leap_year());
748    /// ```
749    #[inline]
750    pub fn in_leap_year(self) -> bool {
751        itime::is_leap_year(self.year())
752    }
753
754    /// Returns the date immediately following this one.
755    ///
756    /// # Errors
757    ///
758    /// This returns an error when this date is the maximum value.
759    ///
760    /// # Example
761    ///
762    /// ```
763    /// use jiff::civil::{Date, date};
764    ///
765    /// let d = date(2024, 2, 28);
766    /// assert_eq!(d.tomorrow()?, date(2024, 2, 29));
767    ///
768    /// // The max doesn't have a tomorrow.
769    /// assert!(Date::MAX.tomorrow().is_err());
770    ///
771    /// # Ok::<(), Box<dyn std::error::Error>>(())
772    /// ```
773    #[inline]
774    pub fn tomorrow(self) -> Result<Date, Error> {
775        if self.day() >= 28 && self.day() == self.days_in_month() {
776            if self.month() == 12 {
777                let year = b::Year::checked_add(self.year(), 1)?;
778                // OK because Jan 1 is valid for all valid years.
779                return Ok(Date::new_unchecked(year, 1, 1));
780            }
781            // OK because the first of every month for a valid year is valid.
782            // Also, `month + 1` is OK because we know `month` must be less
783            // than `12`.
784            return Ok(Date::new_unchecked(self.year(), self.month() + 1, 1));
785        }
786        // OK because we know `self.day() + 1 <= 28` because of the condition
787        // checked above. Moreover, `28` is a valid day for all valid years
788        // and months.
789        Ok(Date::new_unchecked(self.year(), self.month(), self.day() + 1))
790    }
791
792    /// Returns the date immediately preceding this one.
793    ///
794    /// # Errors
795    ///
796    /// This returns an error when this date is the minimum value.
797    ///
798    /// # Example
799    ///
800    /// ```
801    /// use jiff::civil::{Date, date};
802    ///
803    /// let d = date(2024, 3, 1);
804    /// assert_eq!(d.yesterday()?, date(2024, 2, 29));
805    ///
806    /// // The min doesn't have a yesterday.
807    /// assert!(Date::MIN.yesterday().is_err());
808    ///
809    /// # Ok::<(), Box<dyn std::error::Error>>(())
810    /// ```
811    #[inline]
812    pub fn yesterday(self) -> Result<Date, Error> {
813        if self.day() == 1 {
814            if self.month() == 1 {
815                let year = b::Year::checked_sub(self.year(), 1)?;
816                // OK because Dec 31 is valid for all valid years.
817                return Ok(Date::new_unchecked(year, 12, 31));
818            }
819            let month = self.month() - 1;
820            // OK because the last of every month for a valid year is valid.
821            // Also, `month - 1` is OK because we know `month` must be greater
822            // than `1`.
823            return Ok(Date::new_unchecked(
824                self.year(),
825                month,
826                itime::days_in_month(self.year(), month),
827            ));
828        }
829        // OK because we know `self.day() - 1 >= 1` because of the condition
830        // checked above. Moreover, since the year/month don't change (since
831        // `self.day() > 1`), subtracting 1 always leads to a valid day for
832        // this month.
833        Ok(Date::new_unchecked(self.year(), self.month(), self.day() - 1))
834    }
835
836    /// Returns the "nth" weekday from the beginning or end of the month in
837    /// which this date resides.
838    ///
839    /// The `nth` parameter can be positive or negative. A positive value
840    /// computes the "nth" weekday from the beginning of the month. A negative
841    /// value computes the "nth" weekday from the end of the month. So for
842    /// example, use `-1` to "find the last weekday" in this date's month.
843    ///
844    /// # Errors
845    ///
846    /// This returns an error when `nth` is `0`, or if it is `5` or `-5` and
847    /// there is no 5th weekday from the beginning or end of the month.
848    ///
849    /// # Example
850    ///
851    /// This shows how to get the nth weekday in a month, starting from the
852    /// beginning of the month:
853    ///
854    /// ```
855    /// use jiff::civil::{Weekday, date};
856    ///
857    /// let month = date(2017, 3, 1);
858    /// let second_friday = month.nth_weekday_of_month(2, Weekday::Friday)?;
859    /// assert_eq!(second_friday, date(2017, 3, 10));
860    ///
861    /// # Ok::<(), Box<dyn std::error::Error>>(())
862    /// ```
863    ///
864    /// This shows how to do the reverse of the above. That is, the nth _last_
865    /// weekday in a month:
866    ///
867    /// ```
868    /// use jiff::civil::{Weekday, date};
869    ///
870    /// let month = date(2024, 3, 1);
871    /// let last_thursday = month.nth_weekday_of_month(-1, Weekday::Thursday)?;
872    /// assert_eq!(last_thursday, date(2024, 3, 28));
873    /// let second_last_thursday = month.nth_weekday_of_month(
874    ///     -2,
875    ///     Weekday::Thursday,
876    /// )?;
877    /// assert_eq!(second_last_thursday, date(2024, 3, 21));
878    ///
879    /// # Ok::<(), Box<dyn std::error::Error>>(())
880    /// ```
881    ///
882    /// This routine can return an error if there isn't an `nth` weekday
883    /// for this month. For example, March 2024 only has 4 Mondays:
884    ///
885    /// ```
886    /// use jiff::civil::{Weekday, date};
887    ///
888    /// let month = date(2024, 3, 25);
889    /// let fourth_monday = month.nth_weekday_of_month(4, Weekday::Monday)?;
890    /// assert_eq!(fourth_monday, date(2024, 3, 25));
891    /// // There is no 5th Monday.
892    /// assert!(month.nth_weekday_of_month(5, Weekday::Monday).is_err());
893    /// // Same goes for counting backwards.
894    /// assert!(month.nth_weekday_of_month(-5, Weekday::Monday).is_err());
895    ///
896    /// # Ok::<(), Box<dyn std::error::Error>>(())
897    /// ```
898    #[inline]
899    pub fn nth_weekday_of_month(
900        self,
901        nth: i8,
902        weekday: Weekday,
903    ) -> Result<Date, Error> {
904        let weekday = weekday.to_iweekday();
905        let idate = self.to_idate_const();
906        Ok(Date::from_idate_const(
907            idate
908                .nth_weekday_of_month(nth, weekday)
909                .map_err(Error::itime_range)?,
910        ))
911    }
912
913    /// Returns the "nth" weekday from this date, not including itself.
914    ///
915    /// The `nth` parameter can be positive or negative. A positive value
916    /// computes the "nth" weekday starting at the day after this date and
917    /// going forwards in time. A negative value computes the "nth" weekday
918    /// starting at the day before this date and going backwards in time.
919    ///
920    /// For example, if this date's weekday is a Sunday and the first Sunday is
921    /// asked for (that is, `date.nth_weekday(1, Weekday::Sunday)`), then the
922    /// result is a week from this date corresponding to the following Sunday.
923    ///
924    /// # Errors
925    ///
926    /// This returns an error when `nth` is `0`, or if it would otherwise
927    /// result in a date that overflows the minimum/maximum values of `Date`.
928    ///
929    /// # Example
930    ///
931    /// This example shows how to find the "nth" weekday going forwards in
932    /// time:
933    ///
934    /// ```
935    /// use jiff::civil::{Weekday, date};
936    ///
937    /// // Use a Sunday in March as our start date.
938    /// let d = date(2024, 3, 10);
939    /// assert_eq!(d.weekday(), Weekday::Sunday);
940    ///
941    /// // The first next Monday is tomorrow!
942    /// let next_monday = d.nth_weekday(1, Weekday::Monday)?;
943    /// assert_eq!(next_monday, date(2024, 3, 11));
944    ///
945    /// // But the next Sunday is a week away, because this doesn't
946    /// // include the current weekday.
947    /// let next_sunday = d.nth_weekday(1, Weekday::Sunday)?;
948    /// assert_eq!(next_sunday, date(2024, 3, 17));
949    ///
950    /// // "not this Thursday, but next Thursday"
951    /// let next_next_thursday = d.nth_weekday(2, Weekday::Thursday)?;
952    /// assert_eq!(next_next_thursday, date(2024, 3, 21));
953    ///
954    /// # Ok::<(), Box<dyn std::error::Error>>(())
955    /// ```
956    ///
957    /// This example shows how to find the "nth" weekday going backwards in
958    /// time:
959    ///
960    /// ```
961    /// use jiff::civil::{Weekday, date};
962    ///
963    /// // Use a Sunday in March as our start date.
964    /// let d = date(2024, 3, 10);
965    /// assert_eq!(d.weekday(), Weekday::Sunday);
966    ///
967    /// // "last Saturday" was yesterday!
968    /// let last_saturday = d.nth_weekday(-1, Weekday::Saturday)?;
969    /// assert_eq!(last_saturday, date(2024, 3, 9));
970    ///
971    /// // "last Sunday" was a week ago.
972    /// let last_sunday = d.nth_weekday(-1, Weekday::Sunday)?;
973    /// assert_eq!(last_sunday, date(2024, 3, 3));
974    ///
975    /// // "not last Thursday, but the one before"
976    /// let prev_prev_thursday = d.nth_weekday(-2, Weekday::Thursday)?;
977    /// assert_eq!(prev_prev_thursday, date(2024, 2, 29));
978    ///
979    /// # Ok::<(), Box<dyn std::error::Error>>(())
980    /// ```
981    ///
982    /// This example shows that overflow results in an error in either
983    /// direction:
984    ///
985    /// ```
986    /// use jiff::civil::{Date, Weekday};
987    ///
988    /// let d = Date::MAX;
989    /// assert_eq!(d.weekday(), Weekday::Friday);
990    /// assert!(d.nth_weekday(1, Weekday::Saturday).is_err());
991    ///
992    /// let d = Date::MIN;
993    /// assert_eq!(d.weekday(), Weekday::Monday);
994    /// assert!(d.nth_weekday(-1, Weekday::Sunday).is_err());
995    /// ```
996    ///
997    /// # Example: the start of Israeli summer time
998    ///
999    /// Israeli law says (at present, as of 2024-03-11) that DST or "summer
1000    /// time" starts on the Friday before the last Sunday in March. We can find
1001    /// that date using both `nth_weekday` and [`Date::nth_weekday_of_month`]:
1002    ///
1003    /// ```
1004    /// use jiff::civil::{Weekday, date};
1005    ///
1006    /// let march = date(2024, 3, 1);
1007    /// let last_sunday = march.nth_weekday_of_month(-1, Weekday::Sunday)?;
1008    /// let dst_starts_on = last_sunday.nth_weekday(-1, Weekday::Friday)?;
1009    /// assert_eq!(dst_starts_on, date(2024, 3, 29));
1010    ///
1011    /// # Ok::<(), Box<dyn std::error::Error>>(())
1012    /// ```
1013    ///
1014    /// # Example: getting the start of the week
1015    ///
1016    /// Given a date, one can use `nth_weekday` to determine the start of the
1017    /// week in which the date resides in. This might vary based on whether
1018    /// the weeks start on Sunday or Monday. This example shows how to handle
1019    /// both.
1020    ///
1021    /// ```
1022    /// use jiff::civil::{Weekday, date};
1023    ///
1024    /// let d = date(2024, 3, 15);
1025    /// // For weeks starting with Sunday.
1026    /// let start_of_week = d.tomorrow()?.nth_weekday(-1, Weekday::Sunday)?;
1027    /// assert_eq!(start_of_week, date(2024, 3, 10));
1028    /// // For weeks starting with Monday.
1029    /// let start_of_week = d.tomorrow()?.nth_weekday(-1, Weekday::Monday)?;
1030    /// assert_eq!(start_of_week, date(2024, 3, 11));
1031    ///
1032    /// # Ok::<(), Box<dyn std::error::Error>>(())
1033    /// ```
1034    ///
1035    /// In the above example, we first get the date after the current one
1036    /// because `nth_weekday` does not consider itself when counting. This
1037    /// works as expected even at the boundaries of a week:
1038    ///
1039    /// ```
1040    /// use jiff::civil::{Weekday, date};
1041    ///
1042    /// // The start of the week.
1043    /// let d = date(2024, 3, 10);
1044    /// let start_of_week = d.tomorrow()?.nth_weekday(-1, Weekday::Sunday)?;
1045    /// assert_eq!(start_of_week, date(2024, 3, 10));
1046    /// // The end of the week.
1047    /// let d = date(2024, 3, 16);
1048    /// let start_of_week = d.tomorrow()?.nth_weekday(-1, Weekday::Sunday)?;
1049    /// assert_eq!(start_of_week, date(2024, 3, 10));
1050    ///
1051    /// # Ok::<(), Box<dyn std::error::Error>>(())
1052    /// ```
1053    #[inline]
1054    pub fn nth_weekday(
1055        self,
1056        nth: i32,
1057        weekday: Weekday,
1058    ) -> Result<Date, Error> {
1059        // ref: http://howardhinnant.github.io/date_algorithms.html#next_weekday
1060
1061        let nth = b::NthWeekday::check(nth)?;
1062        if nth == 0 {
1063            Err(b::NthWeekday::error().into())
1064        } else if nth > 0 {
1065            let weekday_diff = i32::from(weekday.since(self.weekday().next()));
1066            let diff = (nth - 1) * 7 + weekday_diff;
1067            let start = self.tomorrow()?.to_unix_epoch_day();
1068            let end = b::UnixEpochDays::checked_add(start, diff)?;
1069            Ok(Date::from_unix_epoch_day(end))
1070        } else {
1071            let weekday_diff =
1072                i32::from(self.weekday().previous().since(weekday));
1073            // OK because of the range on `NthWeekday`.
1074            let nth = nth.abs();
1075            let diff = (nth - 1) * 7 + weekday_diff;
1076            let start = self.yesterday()?.to_unix_epoch_day();
1077            let end = b::UnixEpochDays::checked_sub(start, diff)?;
1078            Ok(Date::from_unix_epoch_day(end))
1079        }
1080    }
1081
1082    /// Construct an [ISO 8601 week date] from this Gregorian date.
1083    ///
1084    /// The [`ISOWeekDate`] type describes itself in more detail, but in
1085    /// brief, the ISO week date calendar system eschews months in favor of
1086    /// weeks.
1087    ///
1088    /// The minimum and maximum values of an `ISOWeekDate` correspond
1089    /// precisely to the minimum and maximum values of a `Date`. Therefore,
1090    /// converting between them is lossless and infallible.
1091    ///
1092    /// This routine is equivalent to [`ISOWeekDate::from_date`].
1093    ///
1094    /// [ISO 8601 week date]: https://en.wikipedia.org/wiki/ISO_week_date
1095    ///
1096    /// # Example
1097    ///
1098    /// This shows a number of examples demonstrating the conversion from a
1099    /// Gregorian date to an ISO 8601 week date:
1100    ///
1101    /// ```
1102    /// use jiff::civil::{Date, Weekday, date};
1103    ///
1104    /// let weekdate = date(1995, 1, 1).iso_week_date();
1105    /// assert_eq!(weekdate.year(), 1994);
1106    /// assert_eq!(weekdate.week(), 52);
1107    /// assert_eq!(weekdate.weekday(), Weekday::Sunday);
1108    ///
1109    /// let weekdate = date(1996, 12, 31).iso_week_date();
1110    /// assert_eq!(weekdate.year(), 1997);
1111    /// assert_eq!(weekdate.week(), 1);
1112    /// assert_eq!(weekdate.weekday(), Weekday::Tuesday);
1113    ///
1114    /// let weekdate = date(2019, 12, 30).iso_week_date();
1115    /// assert_eq!(weekdate.year(), 2020);
1116    /// assert_eq!(weekdate.week(), 1);
1117    /// assert_eq!(weekdate.weekday(), Weekday::Monday);
1118    ///
1119    /// let weekdate = date(2024, 3, 9).iso_week_date();
1120    /// assert_eq!(weekdate.year(), 2024);
1121    /// assert_eq!(weekdate.week(), 10);
1122    /// assert_eq!(weekdate.weekday(), Weekday::Saturday);
1123    ///
1124    /// let weekdate = Date::MIN.iso_week_date();
1125    /// assert_eq!(weekdate.year(), -9999);
1126    /// assert_eq!(weekdate.week(), 1);
1127    /// assert_eq!(weekdate.weekday(), Weekday::Monday);
1128    ///
1129    /// let weekdate = Date::MAX.iso_week_date();
1130    /// assert_eq!(weekdate.year(), 9999);
1131    /// assert_eq!(weekdate.week(), 52);
1132    /// assert_eq!(weekdate.weekday(), Weekday::Friday);
1133    /// ```
1134    #[inline]
1135    pub fn iso_week_date(self) -> ISOWeekDate {
1136        let days = self.to_unix_epoch_day();
1137        let year = self.year();
1138        let mut week_start = iso_week_start_from_year(year);
1139        if days < week_start {
1140            week_start = iso_week_start_from_year(year - 1);
1141        } else if year < b::Year::MAX {
1142            let next_year_week_start = iso_week_start_from_year(year + 1);
1143            if days >= next_year_week_start {
1144                week_start = next_year_week_start;
1145            }
1146        }
1147
1148        let weekday =
1149            Weekday::from_iweekday(IEpochDay { epoch_day: days }.weekday());
1150        let week = i8::try_from(((days - week_start) / 7) + 1).unwrap();
1151
1152        let unix_epoch_day =
1153            week_start + i32::from(Weekday::Thursday.since(Weekday::Monday));
1154        let year = Date::from_unix_epoch_day(unix_epoch_day).year();
1155        ISOWeekDate::new(year, week, weekday)
1156            .expect("all Dates infallibly convert to ISOWeekDates")
1157    }
1158
1159    /// Converts a civil date to a [`Zoned`] datetime by adding the given
1160    /// time zone and setting the clock time to midnight.
1161    ///
1162    /// This is a convenience function for
1163    /// `date.to_datetime(midnight).in_tz(name)`. See [`DateTime::to_zoned`]
1164    /// for more details. Note that ambiguous datetimes are handled in the
1165    /// same way as `DateTime::to_zoned`.
1166    ///
1167    /// # Errors
1168    ///
1169    /// This returns an error when the given time zone name could not be found
1170    /// in the default time zone database.
1171    ///
1172    /// This also returns an error if this date could not be represented as
1173    /// a timestamp. This can occur in some cases near the minimum and maximum
1174    /// boundaries of a `Date`.
1175    ///
1176    /// # Example
1177    ///
1178    /// This is a simple example of converting a civil date (a "wall" or
1179    /// "local" or "naive" date) to a precise instant in time that is aware of
1180    /// its time zone:
1181    ///
1182    /// ```
1183    /// use jiff::civil::date;
1184    ///
1185    /// let zdt = date(2024, 6, 20).in_tz("America/New_York")?;
1186    /// assert_eq!(zdt.to_string(), "2024-06-20T00:00:00-04:00[America/New_York]");
1187    ///
1188    /// # Ok::<(), Box<dyn std::error::Error>>(())
1189    /// ```
1190    ///
1191    /// # Example: dealing with ambiguity
1192    ///
1193    /// Since a [`Zoned`] corresponds to a precise instant in time (to
1194    /// nanosecond precision) and a `Date` can be many possible such instants,
1195    /// this routine chooses one for this date: the first one, or midnight.
1196    ///
1197    /// Interestingly, some regions implement their daylight saving time
1198    /// transitions at midnight. This means there are some places in the world
1199    /// where, once a year, midnight does not exist on their clocks. As a
1200    /// result, it's possible for the datetime string representing a [`Zoned`]
1201    /// to be something other than midnight. For example:
1202    ///
1203    /// ```
1204    /// use jiff::civil::date;
1205    ///
1206    /// let zdt = date(2024, 3, 10).in_tz("Cuba")?;
1207    /// assert_eq!(zdt.to_string(), "2024-03-10T01:00:00-04:00[Cuba]");
1208    ///
1209    /// # Ok::<(), Box<dyn std::error::Error>>(())
1210    /// ```
1211    ///
1212    /// Since this uses
1213    /// [`Disambiguation::Compatible`](crate::tz::Disambiguation::Compatible),
1214    /// and since that also chooses the "later" time in a forward transition,
1215    /// it follows that the date of the returned `Zoned` will always match
1216    /// this civil date. (Unless there is a pathological time zone with a 24+
1217    /// hour transition forward.)
1218    ///
1219    /// But if a different disambiguation strategy is used, even when only
1220    /// dealing with standard one hour transitions, the date returned can be
1221    /// different:
1222    ///
1223    /// ```
1224    /// use jiff::{civil::date, tz::TimeZone};
1225    ///
1226    /// let tz = TimeZone::get("Cuba")?;
1227    /// let dt = date(2024, 3, 10).at(0, 0, 0, 0);
1228    /// let zdt = tz.to_ambiguous_zoned(dt).earlier()?;
1229    /// assert_eq!(zdt.to_string(), "2024-03-09T23:00:00-05:00[Cuba]");
1230    ///
1231    /// # Ok::<(), Box<dyn std::error::Error>>(())
1232    /// ```
1233    #[inline]
1234    pub fn in_tz(self, time_zone_name: &str) -> Result<Zoned, Error> {
1235        let tz = crate::tz::db().get(time_zone_name)?;
1236        self.to_zoned(tz)
1237    }
1238
1239    /// Converts a civil datetime to a [`Zoned`] datetime by adding the given
1240    /// [`TimeZone`] and setting the clock time to midnight.
1241    ///
1242    /// This is a convenience function for
1243    /// `date.to_datetime(midnight).to_zoned(tz)`. See [`DateTime::to_zoned`]
1244    /// for more details. Note that ambiguous datetimes are handled in the same
1245    /// way as `DateTime::to_zoned`.
1246    ///
1247    /// In the common case of a time zone being represented as a name string,
1248    /// like `Australia/Tasmania`, consider using [`Date::in_tz`]
1249    /// instead.
1250    ///
1251    /// # Errors
1252    ///
1253    /// This returns an error if this date could not be represented as a
1254    /// timestamp. This can occur in some cases near the minimum and maximum
1255    /// boundaries of a `Date`.
1256    ///
1257    /// # Example
1258    ///
1259    /// This example shows how to create a zoned value with a fixed time zone
1260    /// offset:
1261    ///
1262    /// ```
1263    /// use jiff::{civil::date, tz};
1264    ///
1265    /// let tz = tz::offset(-4).to_time_zone();
1266    /// let zdt = date(2024, 6, 20).to_zoned(tz)?;
1267    /// // A time zone annotation is still included in the printable version
1268    /// // of the Zoned value, but it is fixed to a particular offset.
1269    /// assert_eq!(zdt.to_string(), "2024-06-20T00:00:00-04:00[-04:00]");
1270    ///
1271    /// # Ok::<(), Box<dyn std::error::Error>>(())
1272    /// ```
1273    #[inline]
1274    pub fn to_zoned(self, tz: TimeZone) -> Result<Zoned, Error> {
1275        DateTime::from(self).to_zoned(tz)
1276    }
1277
1278    /// Given a [`Time`], this constructs a [`DateTime`] value with its time
1279    /// component equal to this time.
1280    ///
1281    /// This is a convenience function for [`DateTime::from_parts`].
1282    ///
1283    /// # Example
1284    ///
1285    /// ```
1286    /// use jiff::civil::{DateTime, date, time};
1287    ///
1288    /// let date = date(2010, 3, 14);
1289    /// let time = time(2, 30, 0, 0);
1290    /// assert_eq!(DateTime::from_parts(date, time), date.to_datetime(time));
1291    /// ```
1292    #[inline]
1293    pub const fn to_datetime(self, time: Time) -> DateTime {
1294        DateTime::from_parts(self, time)
1295    }
1296
1297    /// A convenience function for constructing a [`DateTime`] from this date
1298    /// at the time given by its components.
1299    ///
1300    /// # Panics
1301    ///
1302    /// This panics if the provided values do not correspond to a valid `Time`.
1303    /// All of the following conditions must be true:
1304    ///
1305    /// * `0 <= hour <= 23`
1306    /// * `0 <= minute <= 59`
1307    /// * `0 <= second <= 59`
1308    /// * `0 <= subsec_nanosecond <= 999,999,999`
1309    ///
1310    /// Similarly, when used in a const context, invalid parameters will
1311    /// prevent your Rust program from compiling.
1312    ///
1313    /// # Example
1314    ///
1315    /// ```
1316    /// use jiff::civil::date;
1317    ///
1318    /// assert_eq!(
1319    ///     date(2010, 3, 14).at(2, 30, 0, 0).to_string(),
1320    ///     "2010-03-14T02:30:00",
1321    /// );
1322    /// ```
1323    ///
1324    /// One can also flip the order by making use of [`Time::on`]:
1325    ///
1326    /// ```
1327    /// use jiff::civil::time;
1328    ///
1329    /// assert_eq!(
1330    ///     time(2, 30, 0, 0).on(2010, 3, 14).to_string(),
1331    ///     "2010-03-14T02:30:00",
1332    /// );
1333    /// ```
1334    #[inline]
1335    pub const fn at(
1336        self,
1337        hour: i8,
1338        minute: i8,
1339        second: i8,
1340        subsec_nanosecond: i32,
1341    ) -> DateTime {
1342        DateTime::from_parts(
1343            self,
1344            Time::constant(hour, minute, second, subsec_nanosecond),
1345        )
1346    }
1347
1348    /// Add the given span of time to this date. If the sum would overflow the
1349    /// minimum or maximum date values, then an error is returned.
1350    ///
1351    /// This operation accepts three different duration types: [`Span`],
1352    /// [`SignedDuration`] or [`std::time::Duration`]. This is achieved via
1353    /// `From` trait implementations for the [`DateArithmetic`] type.
1354    ///
1355    /// # Properties
1356    ///
1357    /// When adding a [`Span`] duration, this routine is _not_ reversible
1358    /// because some additions may be ambiguous. For example, adding `1 month`
1359    /// to the date `2024-03-31` will produce `2024-04-30` since April has only
1360    /// 30 days in a month. Conversely, subtracting `1 month` from `2024-04-30`
1361    /// will produce `2024-03-30`, which is not the date we started with.
1362    ///
1363    /// If spans of time are limited to units of days (or less), then this
1364    /// routine _is_ reversible. This also implies that all operations with
1365    /// a [`SignedDuration`] or a [`std::time::Duration`] are reversible.
1366    ///
1367    /// # Errors
1368    ///
1369    /// If the span added to this date would result in a date that exceeds the
1370    /// range of a `Date`, then this will return an error.
1371    ///
1372    /// # Examples
1373    ///
1374    /// This shows a few examples of adding spans of time to various dates.
1375    /// We make use of the [`ToSpan`](crate::ToSpan) trait for convenient
1376    /// creation of spans.
1377    ///
1378    /// ```
1379    /// use jiff::{civil::date, ToSpan};
1380    ///
1381    /// let d = date(2024, 3, 31);
1382    /// assert_eq!(d.checked_add(1.months())?, date(2024, 4, 30));
1383    /// // Adding two months gives us May 31, not May 30.
1384    /// let d = date(2024, 3, 31);
1385    /// assert_eq!(d.checked_add(2.months())?, date(2024, 5, 31));
1386    /// // Any time in the span that does not exceed a day is ignored.
1387    /// let d = date(2024, 3, 31);
1388    /// assert_eq!(d.checked_add(23.hours())?, date(2024, 3, 31));
1389    /// // But if the time exceeds a day, that is accounted for!
1390    /// let d = date(2024, 3, 31);
1391    /// assert_eq!(d.checked_add(28.hours())?, date(2024, 4, 1));
1392    ///
1393    /// # Ok::<(), Box<dyn std::error::Error>>(())
1394    /// ```
1395    ///
1396    /// # Example: available via addition operator
1397    ///
1398    /// This routine can be used via the `+` operator. Note though that if it
1399    /// fails, it will result in a panic.
1400    ///
1401    /// ```
1402    /// use jiff::{civil::date, ToSpan};
1403    ///
1404    /// let d = date(2024, 3, 31);
1405    /// assert_eq!(d + 1.months(), date(2024, 4, 30));
1406    /// ```
1407    ///
1408    /// # Example: negative spans are supported
1409    ///
1410    /// ```
1411    /// use jiff::{civil::date, ToSpan};
1412    ///
1413    /// let d = date(2024, 3, 31);
1414    /// assert_eq!(
1415    ///     d.checked_add(-1.months())?,
1416    ///     date(2024, 2, 29),
1417    /// );
1418    /// # Ok::<(), Box<dyn std::error::Error>>(())
1419    /// ```
1420    ///
1421    /// # Example: error on overflow
1422    ///
1423    /// ```
1424    /// use jiff::{civil::date, ToSpan};
1425    ///
1426    /// let d = date(2024, 3, 31);
1427    /// assert!(d.checked_add(9000.years()).is_err());
1428    /// assert!(d.checked_add(-19000.years()).is_err());
1429    /// ```
1430    ///
1431    /// # Example: adding absolute durations
1432    ///
1433    /// This shows how to add signed and unsigned absolute durations to a
1434    /// `Date`. Only whole numbers of days are considered. Since this is a
1435    /// civil date unaware of time zones, days are always 24 hours.
1436    ///
1437    /// ```
1438    /// use std::time::Duration;
1439    ///
1440    /// use jiff::{civil::date, SignedDuration};
1441    ///
1442    /// let d = date(2024, 2, 29);
1443    ///
1444    /// let dur = SignedDuration::from_hours(24);
1445    /// assert_eq!(d.checked_add(dur)?, date(2024, 3, 1));
1446    /// assert_eq!(d.checked_add(-dur)?, date(2024, 2, 28));
1447    ///
1448    /// // Any leftover time is truncated. That is, only
1449    /// // whole days from the duration are considered.
1450    /// let dur = Duration::from_secs((24 * 60 * 60) + (23 * 60 * 60));
1451    /// assert_eq!(d.checked_add(dur)?, date(2024, 3, 1));
1452    ///
1453    /// # Ok::<(), Box<dyn std::error::Error>>(())
1454    /// ```
1455    #[inline]
1456    pub fn checked_add<A: Into<DateArithmetic>>(
1457        self,
1458        duration: A,
1459    ) -> Result<Date, Error> {
1460        let duration: DateArithmetic = duration.into();
1461        duration.checked_add(self)
1462    }
1463
1464    #[inline]
1465    fn checked_add_span(self, span: &Span) -> Result<Date, Error> {
1466        if span.is_zero() {
1467            return Ok(self);
1468        }
1469        if span.units().contains_only(Unit::Day) {
1470            let days = span.get_days();
1471            return if days == -1 {
1472                self.yesterday()
1473            } else if days == 1 {
1474                self.tomorrow()
1475            } else {
1476                let epoch_days = self.to_unix_epoch_day();
1477                let days = b::UnixEpochDays::checked_add(epoch_days, days)?;
1478                Ok(Date::from_unix_epoch_day(days))
1479            };
1480        }
1481
1482        let (month, years) =
1483            month_add_overflowing(self.month(), span.get_months());
1484        let year = b::Year::checked_add(self.year(), years)
1485            .and_then(|years| b::Year::checked_add(years, span.get_years()))?;
1486        let date = Date::new_constrain(year, month, self.day())?;
1487        let epoch_days = date.to_unix_epoch_day();
1488        let mut days =
1489            b::UnixEpochDays::checked_add(epoch_days, 7 * span.get_weeks())
1490                .and_then(|days| {
1491                    b::UnixEpochDays::checked_add(days, span.get_days())
1492                })?;
1493        if !span.units().only_time().is_empty() {
1494            let time_days = b::UnixEpochDays::check(
1495                span.to_invariant_duration_time_only().as_civil_days(),
1496            )?;
1497            days = b::UnixEpochDays::checked_add(days, time_days)?;
1498        }
1499        Ok(Date::from_unix_epoch_day(days))
1500    }
1501
1502    #[inline]
1503    fn checked_add_duration(
1504        self,
1505        duration: SignedDuration,
1506    ) -> Result<Date, Error> {
1507        match duration.as_civil_days() {
1508            0 => Ok(self),
1509            -1 => self.yesterday(),
1510            1 => self.tomorrow(),
1511            days => {
1512                let days = b::UnixEpochDays::check(days)
1513                    .context(E::OverflowDaysDuration)?;
1514                let days = b::UnixEpochDays::checked_add(
1515                    days,
1516                    self.to_unix_epoch_day(),
1517                )?;
1518                Ok(Date::from_unix_epoch_day(days))
1519            }
1520        }
1521    }
1522
1523    /// This routine is identical to [`Date::checked_add`] with the duration
1524    /// negated.
1525    ///
1526    /// # Errors
1527    ///
1528    /// This has the same error conditions as [`Date::checked_add`].
1529    ///
1530    /// # Example
1531    ///
1532    /// ```
1533    /// use std::time::Duration;
1534    ///
1535    /// use jiff::{civil::date, SignedDuration, ToSpan};
1536    ///
1537    /// let d = date(2024, 2, 29);
1538    /// assert_eq!(d.checked_sub(1.year())?, date(2023, 2, 28));
1539    ///
1540    /// let dur = SignedDuration::from_hours(24);
1541    /// assert_eq!(d.checked_sub(dur)?, date(2024, 2, 28));
1542    ///
1543    /// let dur = Duration::from_secs(24 * 60 * 60);
1544    /// assert_eq!(d.checked_sub(dur)?, date(2024, 2, 28));
1545    ///
1546    /// # Ok::<(), Box<dyn std::error::Error>>(())
1547    /// ```
1548    #[inline]
1549    pub fn checked_sub<A: Into<DateArithmetic>>(
1550        self,
1551        duration: A,
1552    ) -> Result<Date, Error> {
1553        let duration: DateArithmetic = duration.into();
1554        duration.checked_neg().and_then(|da| da.checked_add(self))
1555    }
1556
1557    /// This routine is identical to [`Date::checked_add`], except the
1558    /// result saturates on overflow. That is, instead of overflow, either
1559    /// [`Date::MIN`] or [`Date::MAX`] is returned.
1560    ///
1561    /// # Example
1562    ///
1563    /// ```
1564    /// use jiff::{civil::{Date, date}, SignedDuration, ToSpan};
1565    ///
1566    /// let d = date(2024, 3, 31);
1567    /// assert_eq!(Date::MAX, d.saturating_add(9000.years()));
1568    /// assert_eq!(Date::MIN, d.saturating_add(-19000.years()));
1569    /// assert_eq!(Date::MAX, d.saturating_add(SignedDuration::MAX));
1570    /// assert_eq!(Date::MIN, d.saturating_add(SignedDuration::MIN));
1571    /// assert_eq!(Date::MAX, d.saturating_add(std::time::Duration::MAX));
1572    /// ```
1573    #[inline]
1574    pub fn saturating_add<A: Into<DateArithmetic>>(self, duration: A) -> Date {
1575        let duration: DateArithmetic = duration.into();
1576        self.checked_add(duration).unwrap_or_else(|_| {
1577            if duration.is_negative() {
1578                Date::MIN
1579            } else {
1580                Date::MAX
1581            }
1582        })
1583    }
1584
1585    /// This routine is identical to [`Date::saturating_add`] with the span
1586    /// parameter negated.
1587    ///
1588    /// # Example
1589    ///
1590    /// ```
1591    /// use jiff::{civil::{Date, date}, SignedDuration, ToSpan};
1592    ///
1593    /// let d = date(2024, 3, 31);
1594    /// assert_eq!(Date::MIN, d.saturating_sub(19000.years()));
1595    /// assert_eq!(Date::MAX, d.saturating_sub(-9000.years()));
1596    /// assert_eq!(Date::MIN, d.saturating_sub(SignedDuration::MAX));
1597    /// assert_eq!(Date::MAX, d.saturating_sub(SignedDuration::MIN));
1598    /// assert_eq!(Date::MIN, d.saturating_sub(std::time::Duration::MAX));
1599    /// ```
1600    #[inline]
1601    pub fn saturating_sub<A: Into<DateArithmetic>>(self, duration: A) -> Date {
1602        let duration: DateArithmetic = duration.into();
1603        let Ok(duration) = duration.checked_neg() else { return Date::MIN };
1604        self.saturating_add(duration)
1605    }
1606
1607    /// Returns a span representing the elapsed time from this date until
1608    /// the given `other` date.
1609    ///
1610    /// When `other` occurs before this date, then the span returned will be
1611    /// negative.
1612    ///
1613    /// Depending on the input provided, the span returned is rounded. It may
1614    /// also be balanced up to bigger units than the default. By default, the
1615    /// span returned is balanced such that the biggest and smallest possible
1616    /// unit is days.
1617    ///
1618    /// This operation is configured by providing a [`DateDifference`]
1619    /// value. Since this routine accepts anything that implements
1620    /// `Into<DateDifference>`, once can pass a `Date` directly. One
1621    /// can also pass a `(Unit, Date)`, where `Unit` is treated as
1622    /// [`DateDifference::largest`].
1623    ///
1624    /// # Properties
1625    ///
1626    /// It is guaranteed that if the returned span is subtracted from `other`,
1627    /// and if no rounding is requested, and if the largest unit request is at
1628    /// most `Unit::Day`, then the original date will be returned.
1629    ///
1630    /// This routine is equivalent to `self.since(other).map(|span| -span)`
1631    /// if no rounding options are set. If rounding options are set, then
1632    /// it's equivalent to
1633    /// `self.since(other_without_rounding_options).map(|span| -span)`,
1634    /// followed by a call to [`Span::round`] with the appropriate rounding
1635    /// options set. This is because the negation of a span can result in
1636    /// different rounding results depending on the rounding mode.
1637    ///
1638    /// # Errors
1639    ///
1640    /// An error can occur if `DateDifference` is misconfigured. For example,
1641    /// if the smallest unit provided is bigger than the largest unit.
1642    ///
1643    /// It is guaranteed that if one provides a date with the default
1644    /// [`DateDifference`] configuration, then this routine will never fail.
1645    ///
1646    /// # Examples
1647    ///
1648    /// ```
1649    /// use jiff::{civil::date, ToSpan};
1650    ///
1651    /// let earlier = date(2006, 8, 24);
1652    /// let later = date(2019, 1, 31);
1653    /// assert_eq!(earlier.until(later)?, 4543.days().fieldwise());
1654    ///
1655    /// // Flipping the dates is fine, but you'll get a negative span.
1656    /// let earlier = date(2006, 8, 24);
1657    /// let later = date(2019, 1, 31);
1658    /// assert_eq!(later.until(earlier)?, -4543.days().fieldwise());
1659    ///
1660    /// # Ok::<(), Box<dyn std::error::Error>>(())
1661    /// ```
1662    ///
1663    /// # Example: using bigger units
1664    ///
1665    /// This example shows how to expand the span returned to bigger units.
1666    /// This makes use of a `From<(Unit, Date)> for DateDifference` trait
1667    /// implementation.
1668    ///
1669    /// ```
1670    /// use jiff::{civil::date, Unit, ToSpan};
1671    ///
1672    /// let d1 = date(1995, 12, 07);
1673    /// let d2 = date(2019, 01, 31);
1674    ///
1675    /// // The default limits durations to using "days" as the biggest unit.
1676    /// let span = d1.until(d2)?;
1677    /// assert_eq!(span.to_string(), "P8456D");
1678    ///
1679    /// // But we can ask for units all the way up to years.
1680    /// let span = d1.until((Unit::Year, d2))?;
1681    /// assert_eq!(span.to_string(), "P23Y1M24D");
1682    ///
1683    /// # Ok::<(), Box<dyn std::error::Error>>(())
1684    /// ```
1685    ///
1686    /// # Example: rounding the result
1687    ///
1688    /// This shows how one might find the difference between two dates and
1689    /// have the result rounded to the nearest month.
1690    ///
1691    /// In this case, we need to hand-construct a [`DateDifference`]
1692    /// in order to gain full configurability.
1693    ///
1694    /// ```
1695    /// use jiff::{civil::{date, DateDifference}, Unit, ToSpan};
1696    ///
1697    /// let d1 = date(1995, 12, 07);
1698    /// let d2 = date(2019, 02, 06);
1699    ///
1700    /// let span = d1.until(DateDifference::from(d2).smallest(Unit::Month))?;
1701    /// assert_eq!(span, 277.months().fieldwise());
1702    ///
1703    /// // Or even include years to make the span a bit more comprehensible.
1704    /// let span = d1.until(
1705    ///     DateDifference::from(d2)
1706    ///         .smallest(Unit::Month)
1707    ///         .largest(Unit::Year),
1708    /// )?;
1709    /// // Notice that we are one day shy of 23y2m. Rounding spans computed
1710    /// // between dates uses truncation by default.
1711    /// assert_eq!(span, 23.years().months(1).fieldwise());
1712    ///
1713    /// # Ok::<(), Box<dyn std::error::Error>>(())
1714    /// ```
1715    ///
1716    /// # Example: units biggers than days inhibit reversibility
1717    ///
1718    /// If you ask for units bigger than days, then adding the span
1719    /// returned to the `other` date is not guaranteed to result in the
1720    /// original date. For example:
1721    ///
1722    /// ```
1723    /// use jiff::{civil::date, Unit, ToSpan};
1724    ///
1725    /// let d1 = date(2024, 3, 2);
1726    /// let d2 = date(2024, 5, 1);
1727    ///
1728    /// let span = d1.until((Unit::Month, d2))?;
1729    /// assert_eq!(span, 1.month().days(29).fieldwise());
1730    /// let maybe_original = d2.checked_sub(span)?;
1731    /// // Not the same as the original datetime!
1732    /// assert_eq!(maybe_original, date(2024, 3, 3));
1733    ///
1734    /// // But in the default configuration, days are always the biggest unit
1735    /// // and reversibility is guaranteed.
1736    /// let span = d1.until(d2)?;
1737    /// assert_eq!(span, 60.days().fieldwise());
1738    /// let is_original = d2.checked_sub(span)?;
1739    /// assert_eq!(is_original, d1);
1740    ///
1741    /// # Ok::<(), Box<dyn std::error::Error>>(())
1742    /// ```
1743    ///
1744    /// This occurs because spans are added as if by adding the biggest units
1745    /// first, and then the smaller units. Because months vary in length,
1746    /// their meaning can change depending on how the span is added. In this
1747    /// case, adding one month to `2024-03-02` corresponds to 31 days, but
1748    /// subtracting one month from `2024-05-01` corresponds to 30 days.
1749    #[inline]
1750    pub fn until<A: Into<DateDifference>>(
1751        self,
1752        other: A,
1753    ) -> Result<Span, Error> {
1754        let args: DateDifference = other.into();
1755        let span = args.since_with_largest_unit(self)?;
1756        if args.rounding_may_change_span() {
1757            span.round(args.round.relative(self))
1758        } else {
1759            Ok(span)
1760        }
1761    }
1762
1763    /// This routine is identical to [`Date::until`], but the order of the
1764    /// parameters is flipped.
1765    ///
1766    /// # Errors
1767    ///
1768    /// This has the same error conditions as [`Date::until`].
1769    ///
1770    /// # Example
1771    ///
1772    /// This routine can be used via the `-` operator. Since the default
1773    /// configuration is used and because a `Span` can represent the difference
1774    /// between any two possible dates, it will never panic.
1775    ///
1776    /// ```
1777    /// use jiff::{civil::date, ToSpan};
1778    ///
1779    /// let earlier = date(2006, 8, 24);
1780    /// let later = date(2019, 1, 31);
1781    /// assert_eq!(later - earlier, 4543.days().fieldwise());
1782    /// // Equivalent to:
1783    /// assert_eq!(later.since(earlier).unwrap(), 4543.days().fieldwise());
1784    /// ```
1785    #[inline]
1786    pub fn since<A: Into<DateDifference>>(
1787        self,
1788        other: A,
1789    ) -> Result<Span, Error> {
1790        let args: DateDifference = other.into();
1791        let span = -args.since_with_largest_unit(self)?;
1792        if args.rounding_may_change_span() {
1793            span.round(args.round.relative(self))
1794        } else {
1795            Ok(span)
1796        }
1797    }
1798
1799    /// Returns an absolute duration representing the elapsed time from this
1800    /// date until the given `other` date.
1801    ///
1802    /// When `other` occurs before this date, then the duration returned will
1803    /// be negative.
1804    ///
1805    /// Unlike [`Date::until`], this returns a duration corresponding to a
1806    /// 96-bit integer of nanoseconds between two dates. In this case of
1807    /// computing durations between civil dates where all days are assumed to
1808    /// be 24 hours long, the duration returned will always be divisible by
1809    /// 24 hours. (That is, `24 * 60 * 60 * 1_000_000_000` nanoseconds.)
1810    ///
1811    /// # Fallibility
1812    ///
1813    /// This routine never panics or returns an error. Since there are no
1814    /// configuration options that can be incorrectly provided, no error is
1815    /// possible when calling this routine. In contrast, [`Date::until`] can
1816    /// return an error in some cases due to misconfiguration. But like this
1817    /// routine, [`Date::until`] never panics or returns an error in its
1818    /// default configuration.
1819    ///
1820    /// # When should I use this versus [`Date::until`]?
1821    ///
1822    /// See the type documentation for [`SignedDuration`] for the section on
1823    /// when one should use [`Span`] and when one should use `SignedDuration`.
1824    /// In short, use `Span` (and therefore `Date::until`) unless you have a
1825    /// specific reason to do otherwise.
1826    ///
1827    /// # Example
1828    ///
1829    /// ```
1830    /// use jiff::{civil::date, SignedDuration};
1831    ///
1832    /// let earlier = date(2006, 8, 24);
1833    /// let later = date(2019, 1, 31);
1834    /// assert_eq!(
1835    ///     earlier.duration_until(later),
1836    ///     SignedDuration::from_hours(4543 * 24),
1837    /// );
1838    /// ```
1839    ///
1840    /// # Example: difference with [`Date::until`]
1841    ///
1842    /// The main difference between this routine and `Date::until` is that the
1843    /// latter can return units other than a 96-bit integer of nanoseconds.
1844    /// While a 96-bit integer of nanoseconds can be converted into other
1845    /// units like hours, this can only be done for uniform units. (Uniform
1846    /// units are units for which each individual unit always corresponds to
1847    /// the same elapsed time regardless of the datetime it is relative to.)
1848    /// This can't be done for units like years, months or days without a
1849    /// relative date.
1850    ///
1851    /// ```
1852    /// use jiff::{civil::date, SignedDuration, Span, SpanRound, ToSpan, Unit};
1853    ///
1854    /// let d1 = date(2024, 1, 1);
1855    /// let d2 = date(2025, 4, 1);
1856    ///
1857    /// let span = d1.until((Unit::Year, d2))?;
1858    /// assert_eq!(span, 1.year().months(3).fieldwise());
1859    ///
1860    /// let duration = d1.duration_until(d2);
1861    /// assert_eq!(duration, SignedDuration::from_hours(456 * 24));
1862    /// // There's no way to extract years or months from the signed
1863    /// // duration like one might extract hours (because every hour
1864    /// // is the same length). Instead, you actually have to convert
1865    /// // it to a span and then balance it by providing a relative date!
1866    /// let options = SpanRound::new().largest(Unit::Year).relative(d1);
1867    /// let span = Span::try_from(duration)?.round(options)?;
1868    /// assert_eq!(span, 1.year().months(3).fieldwise());
1869    ///
1870    /// # Ok::<(), Box<dyn std::error::Error>>(())
1871    /// ```
1872    ///
1873    /// # Example: getting an unsigned duration
1874    ///
1875    /// If you're looking to find the duration between two dates as a
1876    /// [`std::time::Duration`], you'll need to use this method to get a
1877    /// [`SignedDuration`] and then convert it to a `std::time::Duration`:
1878    ///
1879    /// ```
1880    /// use std::time::Duration;
1881    ///
1882    /// use jiff::{civil::date, SignedDuration};
1883    ///
1884    /// let d1 = date(2024, 7, 1);
1885    /// let d2 = date(2024, 8, 1);
1886    /// let duration = Duration::try_from(d1.duration_until(d2))?;
1887    /// assert_eq!(duration, Duration::from_secs(31 * 24 * 60 * 60));
1888    ///
1889    /// // Note that unsigned durations cannot represent all
1890    /// // possible differences! If the duration would be negative,
1891    /// // then the conversion fails:
1892    /// assert!(Duration::try_from(d2.duration_until(d1)).is_err());
1893    ///
1894    /// # Ok::<(), Box<dyn std::error::Error>>(())
1895    /// ```
1896    #[inline]
1897    pub fn duration_until(self, other: Date) -> SignedDuration {
1898        SignedDuration::date_until(self, other)
1899    }
1900
1901    /// This routine is identical to [`Date::duration_until`], but the order of
1902    /// the parameters is flipped.
1903    ///
1904    /// # Example
1905    ///
1906    /// ```
1907    /// use jiff::{civil::date, SignedDuration};
1908    ///
1909    /// let earlier = date(2006, 8, 24);
1910    /// let later = date(2019, 1, 31);
1911    /// assert_eq!(
1912    ///     later.duration_since(earlier),
1913    ///     SignedDuration::from_hours(4543 * 24),
1914    /// );
1915    /// ```
1916    #[inline]
1917    pub fn duration_since(self, other: Date) -> SignedDuration {
1918        SignedDuration::date_until(other, self)
1919    }
1920
1921    /// Return an iterator of periodic dates determined by the given span.
1922    ///
1923    /// The given span may be negative, in which case, the iterator will move
1924    /// backwards through time. The iterator won't stop until either the span
1925    /// itself overflows, or it would otherwise exceed the minimum or maximum
1926    /// `Date` value.
1927    ///
1928    /// # Example: Halloween day of the week
1929    ///
1930    /// As a kid, I always hoped for Halloween to fall on a weekend. With this
1931    /// program, we can print the day of the week for all Halloweens in the
1932    /// 2020s.
1933    ///
1934    /// ```
1935    /// use jiff::{civil::{Weekday, date}, ToSpan};
1936    ///
1937    /// let start = date(2020, 10, 31);
1938    /// let mut halloween_days_of_week = vec![];
1939    /// for halloween in start.series(1.years()).take(10) {
1940    ///     halloween_days_of_week.push(
1941    ///         (halloween.year(), halloween.weekday()),
1942    ///     );
1943    /// }
1944    /// assert_eq!(halloween_days_of_week, vec![
1945    ///     (2020, Weekday::Saturday),
1946    ///     (2021, Weekday::Sunday),
1947    ///     (2022, Weekday::Monday),
1948    ///     (2023, Weekday::Tuesday),
1949    ///     (2024, Weekday::Thursday),
1950    ///     (2025, Weekday::Friday),
1951    ///     (2026, Weekday::Saturday),
1952    ///     (2027, Weekday::Sunday),
1953    ///     (2028, Weekday::Tuesday),
1954    ///     (2029, Weekday::Wednesday),
1955    /// ]);
1956    /// ```
1957    ///
1958    /// # Example: how many times do I mow the lawn in a year?
1959    ///
1960    /// I mow the lawn about every week and a half from the beginning of May
1961    /// to the end of October. About how many times will I mow the lawn in
1962    /// 2024?
1963    ///
1964    /// ```
1965    /// use jiff::{ToSpan, civil::date};
1966    ///
1967    /// let start = date(2024, 5, 1);
1968    /// let end = date(2024, 10, 31);
1969    /// let mows = start
1970    ///     .series(1.weeks().days(3).hours(12))
1971    ///     .take_while(|&d| d <= end)
1972    ///     .count();
1973    /// assert_eq!(mows, 18);
1974    /// ```
1975    ///
1976    /// # Example: a period less than a day
1977    ///
1978    /// Using a period less than a day works, but since this type exists at the
1979    /// granularity of a day, some dates may be repeated.
1980    ///
1981    /// ```
1982    /// use jiff::{civil::{Date, date}, ToSpan};
1983    ///
1984    /// let start = date(2024, 3, 11);
1985    /// let every_five_hours: Vec<Date> =
1986    ///     start.series(15.hours()).take(7).collect();
1987    /// assert_eq!(every_five_hours, vec![
1988    ///     date(2024, 3, 11),
1989    ///     date(2024, 3, 11),
1990    ///     date(2024, 3, 12),
1991    ///     date(2024, 3, 12),
1992    ///     date(2024, 3, 13),
1993    ///     date(2024, 3, 14),
1994    ///     date(2024, 3, 14),
1995    /// ]);
1996    /// ```
1997    ///
1998    /// # Example: finding the most recent Friday the 13th
1999    ///
2000    /// When did the most recent Friday the 13th occur?
2001    ///
2002    /// ```
2003    /// use jiff::{civil::{Weekday, date}, ToSpan};
2004    ///
2005    /// let start = date(2024, 3, 13);
2006    /// let mut found = None;
2007    /// for date in start.series(-1.months()) {
2008    ///     if date.weekday() == Weekday::Friday {
2009    ///         found = Some(date);
2010    ///         break;
2011    ///     }
2012    /// }
2013    /// assert_eq!(found, Some(date(2023, 10, 13)));
2014    /// ```
2015    #[inline]
2016    pub fn series(self, period: Span) -> DateSeries {
2017        DateSeries { start: self, period, step: 0 }
2018    }
2019}
2020
2021/// Parsing and formatting using a "printf"-style API.
2022impl Date {
2023    /// Parses a civil date in `input` matching the given `format`.
2024    ///
2025    /// The format string uses a "printf"-style API where conversion
2026    /// specifiers can be used as place holders to match components of
2027    /// a datetime. For details on the specifiers supported, see the
2028    /// [`fmt::strtime`] module documentation.
2029    ///
2030    /// # Errors
2031    ///
2032    /// This returns an error when parsing failed. This might happen because
2033    /// the format string itself was invalid, or because the input didn't match
2034    /// the format string.
2035    ///
2036    /// This also returns an error if there wasn't sufficient information to
2037    /// construct a civil date. For example, if an offset wasn't parsed.
2038    ///
2039    /// # Example
2040    ///
2041    /// This example shows how to parse a civil date:
2042    ///
2043    /// ```
2044    /// use jiff::civil::Date;
2045    ///
2046    /// // Parse an American date with a two-digit year.
2047    /// let date = Date::strptime("%m/%d/%y", "7/14/24")?;
2048    /// assert_eq!(date.to_string(), "2024-07-14");
2049    ///
2050    /// # Ok::<(), Box<dyn std::error::Error>>(())
2051    /// ```
2052    #[inline]
2053    pub fn strptime(
2054        format: impl AsRef<[u8]>,
2055        input: impl AsRef<[u8]>,
2056    ) -> Result<Date, Error> {
2057        fmt::strtime::parse(format, input).and_then(|tm| tm.to_date())
2058    }
2059
2060    /// Formats this civil date according to the given `format`.
2061    ///
2062    /// The format string uses a "printf"-style API where conversion
2063    /// specifiers can be used as place holders to format components of
2064    /// a datetime. For details on the specifiers supported, see the
2065    /// [`fmt::strtime`] module documentation.
2066    ///
2067    /// # Errors and panics
2068    ///
2069    /// While this routine itself does not error or panic, using the value
2070    /// returned may result in a panic if formatting fails. See the
2071    /// documentation on [`fmt::strtime::Display`] for more information.
2072    ///
2073    /// To format in a way that surfaces errors without panicking, use either
2074    /// [`fmt::strtime::format`] or [`fmt::strtime::BrokenDownTime::format`].
2075    ///
2076    /// # Example
2077    ///
2078    /// This example shows how to format a civil date:
2079    ///
2080    /// ```
2081    /// use jiff::civil::date;
2082    ///
2083    /// let date = date(2024, 7, 15);
2084    /// let string = date.strftime("%Y-%m-%d is a %A").to_string();
2085    /// assert_eq!(string, "2024-07-15 is a Monday");
2086    /// ```
2087    #[inline]
2088    pub fn strftime<'f, F: 'f + ?Sized + AsRef<[u8]>>(
2089        &self,
2090        format: &'f F,
2091    ) -> fmt::strtime::Display<'f> {
2092        fmt::strtime::Display { fmt: format.as_ref(), tm: (*self).into() }
2093    }
2094}
2095
2096/// Internal APIs.
2097impl Date {
2098    #[inline]
2099    pub(crate) fn until_days(self, other: Date) -> i32 {
2100        if self == other {
2101            return 0;
2102        }
2103        let start = self.to_unix_epoch_day();
2104        let end = other.to_unix_epoch_day();
2105        end - start
2106    }
2107
2108    #[cfg_attr(feature = "perf-inline", inline(always))]
2109    pub(crate) fn to_unix_epoch_day(self) -> i32 {
2110        self.to_idate_const().to_epoch_day().epoch_day
2111    }
2112
2113    #[cfg_attr(feature = "perf-inline", inline(always))]
2114    pub(crate) fn from_unix_epoch_day(epoch_day: i32) -> Date {
2115        Date::from_idate_const(IEpochDay { epoch_day }.to_date())
2116    }
2117
2118    #[inline]
2119    pub(crate) const fn to_idate_const(self) -> IDate {
2120        IDate { year: self.year, month: self.month, day: self.day }
2121    }
2122
2123    #[inline]
2124    pub(crate) const fn from_idate_const(idate: IDate) -> Date {
2125        Date { year: idate.year, month: idate.month, day: idate.day }
2126    }
2127}
2128
2129impl Default for Date {
2130    fn default() -> Date {
2131        Date::ZERO
2132    }
2133}
2134
2135impl core::fmt::Debug for Date {
2136    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2137        core::fmt::Display::fmt(self, f)
2138    }
2139}
2140
2141impl core::fmt::Display for Date {
2142    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
2143        use crate::fmt::StdFmtWrite;
2144
2145        DEFAULT_DATETIME_PRINTER
2146            .print_date(self, StdFmtWrite(f))
2147            .map_err(|_| core::fmt::Error)
2148    }
2149}
2150
2151impl core::str::FromStr for Date {
2152    type Err = Error;
2153
2154    fn from_str(string: &str) -> Result<Date, Error> {
2155        DEFAULT_DATETIME_PARSER.parse_date(string)
2156    }
2157}
2158
2159impl From<ISOWeekDate> for Date {
2160    #[inline]
2161    fn from(weekdate: ISOWeekDate) -> Date {
2162        Date::from_iso_week_date(weekdate)
2163    }
2164}
2165
2166impl From<DateTime> for Date {
2167    #[inline]
2168    fn from(dt: DateTime) -> Date {
2169        dt.date()
2170    }
2171}
2172
2173impl From<Zoned> for Date {
2174    #[inline]
2175    fn from(zdt: Zoned) -> Date {
2176        zdt.datetime().date()
2177    }
2178}
2179
2180impl<'a> From<&'a Zoned> for Date {
2181    #[inline]
2182    fn from(zdt: &'a Zoned) -> Date {
2183        zdt.datetime().date()
2184    }
2185}
2186
2187/// Adds a span of time to a date.
2188///
2189/// This uses checked arithmetic and panics on overflow. To handle overflow
2190/// without panics, use [`Date::checked_add`].
2191impl core::ops::Add<Span> for Date {
2192    type Output = Date;
2193
2194    #[inline]
2195    fn add(self, rhs: Span) -> Date {
2196        self.checked_add(rhs).expect("adding span to date overflowed")
2197    }
2198}
2199
2200/// Adds a span of time to a date in place.
2201///
2202/// This uses checked arithmetic and panics on overflow. To handle overflow
2203/// without panics, use [`Date::checked_add`].
2204impl core::ops::AddAssign<Span> for Date {
2205    #[inline]
2206    fn add_assign(&mut self, rhs: Span) {
2207        *self = *self + rhs;
2208    }
2209}
2210
2211/// Subtracts a span of time from a date.
2212///
2213/// This uses checked arithmetic and panics on overflow. To handle overflow
2214/// without panics, use [`Date::checked_sub`].
2215impl core::ops::Sub<Span> for Date {
2216    type Output = Date;
2217
2218    #[inline]
2219    fn sub(self, rhs: Span) -> Date {
2220        self.checked_sub(rhs).expect("subing span to date overflowed")
2221    }
2222}
2223
2224/// Subtracts a span of time from a date in place.
2225///
2226/// This uses checked arithmetic and panics on overflow. To handle overflow
2227/// without panics, use [`Date::checked_sub`].
2228impl core::ops::SubAssign<Span> for Date {
2229    #[inline]
2230    fn sub_assign(&mut self, rhs: Span) {
2231        *self = *self - rhs;
2232    }
2233}
2234
2235/// Computes the span of time between two dates.
2236///
2237/// This will return a negative span when the date being subtracted is greater.
2238///
2239/// Since this uses the default configuration for calculating a span between
2240/// two date (no rounding and largest units is days), this will never panic or
2241/// fail in any way.
2242///
2243/// To configure the largest unit or enable rounding, use [`Date::since`].
2244impl core::ops::Sub for Date {
2245    type Output = Span;
2246
2247    #[inline]
2248    fn sub(self, rhs: Date) -> Span {
2249        self.since(rhs).expect("since never fails when given Date")
2250    }
2251}
2252
2253/// Adds a signed duration of time to a date.
2254///
2255/// This uses checked arithmetic and panics on overflow. To handle overflow
2256/// without panics, use [`Date::checked_add`].
2257impl core::ops::Add<SignedDuration> for Date {
2258    type Output = Date;
2259
2260    #[inline]
2261    fn add(self, rhs: SignedDuration) -> Date {
2262        self.checked_add(rhs)
2263            .expect("adding signed duration to date overflowed")
2264    }
2265}
2266
2267/// Adds a signed duration of time to a date in place.
2268///
2269/// This uses checked arithmetic and panics on overflow. To handle overflow
2270/// without panics, use [`Date::checked_add`].
2271impl core::ops::AddAssign<SignedDuration> for Date {
2272    #[inline]
2273    fn add_assign(&mut self, rhs: SignedDuration) {
2274        *self = *self + rhs;
2275    }
2276}
2277
2278/// Subtracts a signed duration of time from a date.
2279///
2280/// This uses checked arithmetic and panics on overflow. To handle overflow
2281/// without panics, use [`Date::checked_sub`].
2282impl core::ops::Sub<SignedDuration> for Date {
2283    type Output = Date;
2284
2285    #[inline]
2286    fn sub(self, rhs: SignedDuration) -> Date {
2287        self.checked_sub(rhs)
2288            .expect("subing signed duration to date overflowed")
2289    }
2290}
2291
2292/// Subtracts a signed duration of time from a date in place.
2293///
2294/// This uses checked arithmetic and panics on overflow. To handle overflow
2295/// without panics, use [`Date::checked_sub`].
2296impl core::ops::SubAssign<SignedDuration> for Date {
2297    #[inline]
2298    fn sub_assign(&mut self, rhs: SignedDuration) {
2299        *self = *self - rhs;
2300    }
2301}
2302
2303/// Adds an unsigned duration of time to a date.
2304///
2305/// This uses checked arithmetic and panics on overflow. To handle overflow
2306/// without panics, use [`Date::checked_add`].
2307impl core::ops::Add<UnsignedDuration> for Date {
2308    type Output = Date;
2309
2310    #[inline]
2311    fn add(self, rhs: UnsignedDuration) -> Date {
2312        self.checked_add(rhs)
2313            .expect("adding unsigned duration to date overflowed")
2314    }
2315}
2316
2317/// Adds an unsigned duration of time to a date in place.
2318///
2319/// This uses checked arithmetic and panics on overflow. To handle overflow
2320/// without panics, use [`Date::checked_add`].
2321impl core::ops::AddAssign<UnsignedDuration> for Date {
2322    #[inline]
2323    fn add_assign(&mut self, rhs: UnsignedDuration) {
2324        *self = *self + rhs;
2325    }
2326}
2327
2328/// Subtracts an unsigned duration of time from a date.
2329///
2330/// This uses checked arithmetic and panics on overflow. To handle overflow
2331/// without panics, use [`Date::checked_sub`].
2332impl core::ops::Sub<UnsignedDuration> for Date {
2333    type Output = Date;
2334
2335    #[inline]
2336    fn sub(self, rhs: UnsignedDuration) -> Date {
2337        self.checked_sub(rhs)
2338            .expect("subing unsigned duration to date overflowed")
2339    }
2340}
2341
2342/// Subtracts an unsigned duration of time from a date in place.
2343///
2344/// This uses checked arithmetic and panics on overflow. To handle overflow
2345/// without panics, use [`Date::checked_sub`].
2346impl core::ops::SubAssign<UnsignedDuration> for Date {
2347    #[inline]
2348    fn sub_assign(&mut self, rhs: UnsignedDuration) {
2349        *self = *self - rhs;
2350    }
2351}
2352
2353#[cfg(feature = "serde")]
2354impl serde_core::Serialize for Date {
2355    #[inline]
2356    fn serialize<S: serde_core::Serializer>(
2357        &self,
2358        serializer: S,
2359    ) -> Result<S::Ok, S::Error> {
2360        serializer.collect_str(self)
2361    }
2362}
2363
2364#[cfg(feature = "serde")]
2365impl<'de> serde_core::Deserialize<'de> for Date {
2366    #[inline]
2367    fn deserialize<D: serde_core::Deserializer<'de>>(
2368        deserializer: D,
2369    ) -> Result<Date, D::Error> {
2370        use serde_core::de;
2371
2372        struct DateVisitor;
2373
2374        impl<'de> de::Visitor<'de> for DateVisitor {
2375            type Value = Date;
2376
2377            fn expecting(
2378                &self,
2379                f: &mut core::fmt::Formatter,
2380            ) -> core::fmt::Result {
2381                f.write_str("a date string")
2382            }
2383
2384            #[inline]
2385            fn visit_bytes<E: de::Error>(
2386                self,
2387                value: &[u8],
2388            ) -> Result<Date, E> {
2389                DEFAULT_DATETIME_PARSER
2390                    .parse_date(value)
2391                    .map_err(de::Error::custom)
2392            }
2393
2394            #[inline]
2395            fn visit_str<E: de::Error>(self, value: &str) -> Result<Date, E> {
2396                self.visit_bytes(value.as_bytes())
2397            }
2398        }
2399
2400        deserializer.deserialize_str(DateVisitor)
2401    }
2402}
2403
2404#[cfg(test)]
2405impl quickcheck::Arbitrary for Date {
2406    fn arbitrary(g: &mut quickcheck::Gen) -> Date {
2407        let year = b::Year::arbitrary(g);
2408        let month = b::Month::arbitrary(g);
2409        let day = b::Day::arbitrary(g);
2410        Date::new_constrain(year, month, day).unwrap()
2411    }
2412
2413    fn shrink(&self) -> alloc::boxed::Box<dyn Iterator<Item = Date>> {
2414        alloc::boxed::Box::new(
2415            (self.year(), self.month(), self.day()).shrink().filter_map(
2416                |(year, month, day)| {
2417                    Date::new_constrain(year, month, day).ok()
2418                },
2419            ),
2420        )
2421    }
2422}
2423
2424/// An iterator over periodic dates, created by [`Date::series`].
2425///
2426/// It is exhausted when the next value would exceed the limits of a [`Span`]
2427/// or [`Date`] value.
2428///
2429/// This iterator is created by [`Date::series`].
2430#[derive(Clone, Debug)]
2431pub struct DateSeries {
2432    start: Date,
2433    period: Span,
2434    step: i64,
2435}
2436
2437impl Iterator for DateSeries {
2438    type Item = Date;
2439
2440    #[inline]
2441    fn next(&mut self) -> Option<Date> {
2442        let span = self.period.checked_mul(self.step).ok()?;
2443        self.step = self.step.checked_add(1)?;
2444        let date = self.start.checked_add(span).ok()?;
2445        Some(date)
2446    }
2447}
2448
2449impl core::iter::FusedIterator for DateSeries {}
2450
2451/// Options for [`Date::checked_add`] and [`Date::checked_sub`].
2452///
2453/// This type provides a way to ergonomically add one of a few different
2454/// duration types to a [`Date`].
2455///
2456/// The main way to construct values of this type is with its `From` trait
2457/// implementations:
2458///
2459/// * `From<Span> for DateArithmetic` adds (or subtracts) the given span to the
2460/// receiver date.
2461/// * `From<SignedDuration> for DateArithmetic` adds (or subtracts)
2462/// the given signed duration to the receiver date.
2463/// * `From<std::time::Duration> for DateArithmetic` adds (or subtracts)
2464/// the given unsigned duration to the receiver date.
2465///
2466/// # Example
2467///
2468/// ```
2469/// use std::time::Duration;
2470///
2471/// use jiff::{civil::date, SignedDuration, ToSpan};
2472///
2473/// let d = date(2024, 2, 29);
2474/// assert_eq!(d.checked_add(1.year())?, date(2025, 2, 28));
2475/// assert_eq!(d.checked_add(SignedDuration::from_hours(24))?, date(2024, 3, 1));
2476/// assert_eq!(d.checked_add(Duration::from_secs(24 * 60 * 60))?, date(2024, 3, 1));
2477///
2478/// # Ok::<(), Box<dyn std::error::Error>>(())
2479/// ```
2480#[derive(Clone, Copy, Debug)]
2481pub struct DateArithmetic {
2482    duration: Duration,
2483}
2484
2485impl DateArithmetic {
2486    #[inline]
2487    fn checked_add(self, date: Date) -> Result<Date, Error> {
2488        match self.duration.to_signed()? {
2489            SDuration::Span(span) => date.checked_add_span(span),
2490            SDuration::Absolute(sdur) => date.checked_add_duration(sdur),
2491        }
2492    }
2493
2494    #[inline]
2495    fn checked_neg(self) -> Result<DateArithmetic, Error> {
2496        let duration = self.duration.checked_neg()?;
2497        Ok(DateArithmetic { duration })
2498    }
2499
2500    #[inline]
2501    fn is_negative(&self) -> bool {
2502        self.duration.is_negative()
2503    }
2504}
2505
2506impl From<Span> for DateArithmetic {
2507    fn from(span: Span) -> DateArithmetic {
2508        let duration = Duration::from(span);
2509        DateArithmetic { duration }
2510    }
2511}
2512
2513impl From<SignedDuration> for DateArithmetic {
2514    fn from(sdur: SignedDuration) -> DateArithmetic {
2515        let duration = Duration::from(sdur);
2516        DateArithmetic { duration }
2517    }
2518}
2519
2520impl From<UnsignedDuration> for DateArithmetic {
2521    fn from(udur: UnsignedDuration) -> DateArithmetic {
2522        let duration = Duration::from(udur);
2523        DateArithmetic { duration }
2524    }
2525}
2526
2527impl<'a> From<&'a Span> for DateArithmetic {
2528    fn from(span: &'a Span) -> DateArithmetic {
2529        DateArithmetic::from(*span)
2530    }
2531}
2532
2533impl<'a> From<&'a SignedDuration> for DateArithmetic {
2534    fn from(sdur: &'a SignedDuration) -> DateArithmetic {
2535        DateArithmetic::from(*sdur)
2536    }
2537}
2538
2539impl<'a> From<&'a UnsignedDuration> for DateArithmetic {
2540    fn from(udur: &'a UnsignedDuration) -> DateArithmetic {
2541        DateArithmetic::from(*udur)
2542    }
2543}
2544
2545/// Options for [`Date::since`] and [`Date::until`].
2546///
2547/// This type provides a way to configure the calculation of spans between two
2548/// [`Date`] values. In particular, both `Date::since` and `Date::until` accept
2549/// anything that implements `Into<DateDifference>`. There are a few key trait
2550/// implementations that make this convenient:
2551///
2552/// * `From<Date> for DateDifference` will construct a configuration consisting
2553/// of just the date. So for example, `date1.until(date2)` will return the span
2554/// from `date1` to `date2`.
2555/// * `From<DateTime> for DateDifference` will construct a configuration
2556/// consisting of just the date from the given datetime. So for example,
2557/// `date.since(datetime)` returns the span from `datetime.date()` to `date`.
2558/// * `From<(Unit, Date)>` is a convenient way to specify the largest units
2559/// that should be present on the span returned. By default, the largest units
2560/// are days. Using this trait implementation is equivalent to
2561/// `DateDifference::new(date).largest(unit)`.
2562/// * `From<(Unit, DateTime)>` is like the one above, but with the date from
2563/// the given datetime.
2564///
2565/// One can also provide a `DateDifference` value directly. Doing so is
2566/// necessary to use the rounding features of calculating a span. For example,
2567/// setting the smallest unit (defaults to [`Unit::Day`]), the rounding mode
2568/// (defaults to [`RoundMode::Trunc`]) and the rounding increment (defaults to
2569/// `1`). The defaults are selected such that no rounding occurs.
2570///
2571/// Rounding a span as part of calculating it is provided as a convenience.
2572/// Callers may choose to round the span as a distinct step via
2573/// [`Span::round`], but callers may need to provide a reference date
2574/// for rounding larger units. By coupling rounding with routines like
2575/// [`Date::since`], the reference date can be set automatically based on
2576/// the input to `Date::since`.
2577///
2578/// # Example
2579///
2580/// This example shows how to round a span between two date to the nearest
2581/// year, with ties breaking away from zero.
2582///
2583/// ```
2584/// use jiff::{civil::{Date, DateDifference}, RoundMode, ToSpan, Unit};
2585///
2586/// let d1 = "2024-03-15".parse::<Date>()?;
2587/// let d2 = "2030-09-13".parse::<Date>()?;
2588/// let span = d1.until(
2589///     DateDifference::new(d2)
2590///         .smallest(Unit::Year)
2591///         .mode(RoundMode::HalfExpand),
2592/// )?;
2593/// assert_eq!(span, 6.years().fieldwise());
2594///
2595/// // If the span were one day longer, it would round up to 7 years.
2596/// let d2 = "2030-09-14".parse::<Date>()?;
2597/// let span = d1.until(
2598///     DateDifference::new(d2)
2599///         .smallest(Unit::Year)
2600///         .mode(RoundMode::HalfExpand),
2601/// )?;
2602/// assert_eq!(span, 7.years().fieldwise());
2603///
2604/// # Ok::<(), Box<dyn std::error::Error>>(())
2605/// ```
2606#[derive(Clone, Copy, Debug)]
2607pub struct DateDifference {
2608    date: Date,
2609    round: SpanRound<'static>,
2610}
2611
2612impl DateDifference {
2613    /// Create a new default configuration for computing the span between
2614    /// the given date and some other date (specified as the receiver in
2615    /// [`Date::since`] or [`Date::until`]).
2616    #[inline]
2617    pub fn new(date: Date) -> DateDifference {
2618        // We use truncation rounding by default since it seems that's
2619        // what is generally expected when computing the difference between
2620        // datetimes.
2621        //
2622        // See: https://github.com/tc39/proposal-temporal/issues/1122
2623        let round =
2624            SpanRound::new().mode(RoundMode::Trunc).smallest(Unit::Day);
2625        DateDifference { date, round }
2626    }
2627
2628    /// Set the smallest units allowed in the span returned.
2629    ///
2630    /// When a largest unit is not specified, then the largest unit is
2631    /// automatically set to be equal to the smallest unit.
2632    ///
2633    /// This defaults to `Unit::Day`.
2634    ///
2635    /// # Errors
2636    ///
2637    /// The smallest units must be no greater than the largest units. If this
2638    /// is violated, then computing a span with this configuration will result
2639    /// in an error.
2640    ///
2641    /// The unit set must also be a calendar unit. Using a time unit will
2642    /// result in an error.
2643    ///
2644    /// # Example
2645    ///
2646    /// This shows how to round a span between two date to the nearest
2647    /// number of weeks.
2648    ///
2649    /// ```
2650    /// use jiff::{civil::{Date, DateDifference}, RoundMode, ToSpan, Unit};
2651    ///
2652    /// let d1 = "2024-03-15".parse::<Date>()?;
2653    /// let d2 = "2030-11-22".parse::<Date>()?;
2654    /// let span = d1.until(
2655    ///     DateDifference::new(d2)
2656    ///         .smallest(Unit::Week)
2657    ///         .largest(Unit::Week)
2658    ///         .mode(RoundMode::HalfExpand),
2659    /// )?;
2660    /// assert_eq!(span, 349.weeks().fieldwise());
2661    ///
2662    /// # Ok::<(), Box<dyn std::error::Error>>(())
2663    /// ```
2664    #[inline]
2665    pub fn smallest(self, unit: Unit) -> DateDifference {
2666        DateDifference { round: self.round.smallest(unit), ..self }
2667    }
2668
2669    /// Set the largest units allowed in the span returned.
2670    ///
2671    /// When a largest unit is not specified, then the largest unit is
2672    /// automatically set to be equal to the smallest unit or `Unit::Day`,
2673    /// whichever is greater. Otherwise, when the largest unit is not
2674    /// specified, it is set to days.
2675    ///
2676    /// Once a largest unit is set, there is no way to change this rounding
2677    /// configuration back to using the "automatic" default. Instead, callers
2678    /// must create a new configuration.
2679    ///
2680    /// # Errors
2681    ///
2682    /// The largest units, when set, must be at least as big as the smallest
2683    /// units (which defaults to [`Unit::Day`]). If this is violated, then
2684    /// computing a span with this configuration will result in an error.
2685    ///
2686    /// The unit set must also be a calendar unit. Using a time unit will
2687    /// result in an error.
2688    ///
2689    /// # Example
2690    ///
2691    /// This shows how to round a span between two date to units no
2692    /// bigger than months.
2693    ///
2694    /// ```
2695    /// use jiff::{civil::{Date, DateDifference}, ToSpan, Unit};
2696    ///
2697    /// let d1 = "2024-03-15".parse::<Date>()?;
2698    /// let d2 = "2030-11-22".parse::<Date>()?;
2699    /// let span = d1.until(
2700    ///     DateDifference::new(d2).largest(Unit::Month),
2701    /// )?;
2702    /// assert_eq!(span, 80.months().days(7).fieldwise());
2703    ///
2704    /// # Ok::<(), Box<dyn std::error::Error>>(())
2705    /// ```
2706    #[inline]
2707    pub fn largest(self, unit: Unit) -> DateDifference {
2708        DateDifference { round: self.round.largest(unit), ..self }
2709    }
2710
2711    /// Set the rounding mode.
2712    ///
2713    /// This defaults to [`RoundMode::Trunc`] since it's plausible that
2714    /// rounding "up" in the context of computing the span between two date
2715    /// could be surprising in a number of cases. The [`RoundMode::HalfExpand`]
2716    /// mode corresponds to typical rounding you might have learned about in
2717    /// school. But a variety of other rounding modes exist.
2718    ///
2719    /// # Example
2720    ///
2721    /// This shows how to always round "up" towards positive infinity.
2722    ///
2723    /// ```
2724    /// use jiff::{civil::{Date, DateDifference}, RoundMode, ToSpan, Unit};
2725    ///
2726    /// let d1 = "2024-01-15".parse::<Date>()?;
2727    /// let d2 = "2024-08-16".parse::<Date>()?;
2728    /// let span = d1.until(
2729    ///     DateDifference::new(d2)
2730    ///         .smallest(Unit::Month)
2731    ///         .mode(RoundMode::Ceil),
2732    /// )?;
2733    /// // Only 7 months and 1 day elapsed, but we asked to always round up!
2734    /// assert_eq!(span, 8.months().fieldwise());
2735    ///
2736    /// // Since `Ceil` always rounds toward positive infinity, the behavior
2737    /// // flips for a negative span.
2738    /// let span = d1.since(
2739    ///     DateDifference::new(d2)
2740    ///         .smallest(Unit::Month)
2741    ///         .mode(RoundMode::Ceil),
2742    /// )?;
2743    /// assert_eq!(span, -7.months().fieldwise());
2744    ///
2745    /// # Ok::<(), Box<dyn std::error::Error>>(())
2746    /// ```
2747    #[inline]
2748    pub fn mode(self, mode: RoundMode) -> DateDifference {
2749        DateDifference { round: self.round.mode(mode), ..self }
2750    }
2751
2752    /// Set the rounding increment for the smallest unit.
2753    ///
2754    /// The default value is `1`. Other values permit rounding the smallest
2755    /// unit to the nearest integer increment specified. For example, if the
2756    /// smallest unit is set to [`Unit::Month`], then a rounding increment of
2757    /// `2` would result in rounding in increments of every other month.
2758    ///
2759    /// # Errors
2760    ///
2761    /// The increment must be greater than zero and less than or equal to
2762    /// `1_000_000_000`.
2763    ///
2764    /// The error will occur when computing the span, and not when setting
2765    /// the increment here.
2766    ///
2767    /// # Example
2768    ///
2769    /// This shows how to round the span between two date to the nearest even
2770    /// month.
2771    ///
2772    /// ```
2773    /// use jiff::{civil::{Date, DateDifference}, RoundMode, ToSpan, Unit};
2774    ///
2775    /// let d1 = "2024-01-15".parse::<Date>()?;
2776    /// let d2 = "2024-08-15".parse::<Date>()?;
2777    /// let span = d1.until(
2778    ///     DateDifference::new(d2)
2779    ///         .smallest(Unit::Month)
2780    ///         .increment(2)
2781    ///         .mode(RoundMode::HalfExpand),
2782    /// )?;
2783    /// assert_eq!(span, 8.months().fieldwise());
2784    ///
2785    /// // If our second date was just one day less, rounding would truncate
2786    /// // down to 6 months!
2787    /// let d2 = "2024-08-14".parse::<Date>()?;
2788    /// let span = d1.until(
2789    ///     DateDifference::new(d2)
2790    ///         .smallest(Unit::Month)
2791    ///         .increment(2)
2792    ///         .mode(RoundMode::HalfExpand),
2793    /// )?;
2794    /// assert_eq!(span, 6.months().fieldwise());
2795    ///
2796    /// # Ok::<(), Box<dyn std::error::Error>>(())
2797    /// ```
2798    #[inline]
2799    pub fn increment(self, increment: i64) -> DateDifference {
2800        DateDifference { round: self.round.increment(increment), ..self }
2801    }
2802
2803    /// Returns true if and only if this configuration could change the span
2804    /// via rounding.
2805    #[inline]
2806    fn rounding_may_change_span(&self) -> bool {
2807        self.round.rounding_calendar_only_may_change_span()
2808    }
2809
2810    /// Returns the span of time since `d1` to the date in this configuration.
2811    /// The biggest units allowed are determined by the `smallest` and
2812    /// `largest` settings, but defaults to `Unit::Day`.
2813    #[inline]
2814    fn since_with_largest_unit(&self, d1: Date) -> Result<Span, Error> {
2815        // N.B. A logical (but inefficient yet easier to understand)
2816        // description of the behavior here can be found in the Temporal spec:
2817        // https://tc39.es/proposal-temporal/#sec-temporal-calendardateuntil
2818        //
2819        // Immense discussion discussing and justifying this behavior:
2820        // https://github.com/tc39/proposal-temporal/issues/2535
2821
2822        let smallest = self.round.get_smallest();
2823        if smallest < Unit::Day {
2824            return Err(Error::from(UnitConfigError::CivilDate {
2825                given: smallest,
2826            }));
2827        }
2828
2829        let largest = self.round.get_largest().unwrap_or(smallest);
2830        if largest < Unit::Day {
2831            return Err(Error::from(UnitConfigError::CivilDate {
2832                given: largest,
2833            }));
2834        }
2835
2836        let d2 = self.date;
2837        if d1 == d2 {
2838            return Ok(Span::new());
2839        }
2840        if largest <= Unit::Week {
2841            let mut weeks: i32 = 0;
2842            let mut days = d1.until_days(d2);
2843            if largest == Unit::Week {
2844                weeks = days / 7;
2845                days %= 7;
2846            }
2847            return Ok(Span::new().weeks(weeks).days(days));
2848        }
2849
2850        let year1 = d1.year();
2851        let month1 = d1.month();
2852        let day1 = d1.day();
2853        let mut year2 = d2.year();
2854        let mut month2 = d2.month();
2855        let day2 = d2.day();
2856
2857        let mut years = year2 - year1;
2858        let mut months = i32::from(month2 - month1);
2859        let mut days = i32::from(day2 - day1);
2860        if years != 0 || months != 0 {
2861            let sign = if years != 0 {
2862                b::Sign::from(years)
2863            } else {
2864                b::Sign::from(months)
2865            };
2866            let mut days_in_month2 = d2.days_in_month();
2867            let mut day_correct = 0;
2868            if b::Sign::from(days) == -sign {
2869                // Justifying this operation as infallible is quite tricky.
2870                // It can only fail in two cases: year2=9999, month2=12 and
2871                // sign=Negative or year2=-9999, month2=1 and sign=Positive. In
2872                // both of those cases, year will overflow its boundaries.
2873                //
2874                // However, neither case is possible. Namely, whenever
2875                // sign=Negative, it follows that either `year1 > year2` or
2876                // `month1 > month2`. But there are no such values of `year1`
2877                // or `month1` that satisfy `year1 > 9999 or month1 > 12`
2878                // because `9999` is the maximum legal year value.
2879                //
2880                // A similar argument follows for sign=Positive and
2881                // `year2=-9999` and `month2=1`. Therefore, this `unwrap()` is
2882                // okay.
2883                let (y, m) = month_add_one(year2, month2, -sign).unwrap();
2884                year2 = y;
2885                month2 = m;
2886
2887                years = year2 - year1;
2888                months = i32::from(month2 - month1);
2889                let original_days_in_month1 = days_in_month2;
2890                days_in_month2 = itime::days_in_month(year2, month2);
2891                day_correct = if sign.is_negative() {
2892                    -original_days_in_month1
2893                } else {
2894                    days_in_month2
2895                };
2896            }
2897
2898            let day0_trunc = i32::from(day1.min(days_in_month2));
2899            days = i32::from(day2) - day0_trunc + i32::from(day_correct);
2900
2901            if years != 0 {
2902                months = i32::from(month2 - month1);
2903                if b::Sign::from(months) == -sign {
2904                    let month_correct = sign * 12;
2905                    year2 -= sign.as_i16();
2906                    years = year2 - year1;
2907
2908                    months = i32::from(month2 - month1) + month_correct;
2909                }
2910            }
2911        }
2912        if largest == Unit::Month && years != 0 {
2913            months =
2914                b::SpanMonths::checked_add(months, i32::from(years) * 12)?;
2915            years = 0;
2916        }
2917        Ok(Span::new().years(years).months(months).days(days))
2918    }
2919}
2920
2921impl From<Date> for DateDifference {
2922    #[inline]
2923    fn from(date: Date) -> DateDifference {
2924        DateDifference::new(date)
2925    }
2926}
2927
2928impl From<DateTime> for DateDifference {
2929    #[inline]
2930    fn from(dt: DateTime) -> DateDifference {
2931        DateDifference::from(Date::from(dt))
2932    }
2933}
2934
2935impl From<Zoned> for DateDifference {
2936    #[inline]
2937    fn from(zdt: Zoned) -> DateDifference {
2938        DateDifference::from(Date::from(zdt))
2939    }
2940}
2941
2942impl<'a> From<&'a Zoned> for DateDifference {
2943    #[inline]
2944    fn from(zdt: &'a Zoned) -> DateDifference {
2945        DateDifference::from(zdt.datetime())
2946    }
2947}
2948
2949impl From<(Unit, Date)> for DateDifference {
2950    #[inline]
2951    fn from((largest, date): (Unit, Date)) -> DateDifference {
2952        DateDifference::from(date).largest(largest)
2953    }
2954}
2955
2956impl From<(Unit, DateTime)> for DateDifference {
2957    #[inline]
2958    fn from((largest, dt): (Unit, DateTime)) -> DateDifference {
2959        DateDifference::from((largest, Date::from(dt)))
2960    }
2961}
2962
2963impl From<(Unit, Zoned)> for DateDifference {
2964    #[inline]
2965    fn from((largest, zdt): (Unit, Zoned)) -> DateDifference {
2966        DateDifference::from((largest, Date::from(zdt)))
2967    }
2968}
2969
2970impl<'a> From<(Unit, &'a Zoned)> for DateDifference {
2971    #[inline]
2972    fn from((largest, zdt): (Unit, &'a Zoned)) -> DateDifference {
2973        DateDifference::from((largest, zdt.datetime()))
2974    }
2975}
2976
2977/// A builder for setting the fields on a [`Date`].
2978///
2979/// This builder is constructed via [`Date::with`].
2980///
2981/// # Example
2982///
2983/// The builder ensures one can chain together the individual components
2984/// of a date without it failing at an intermediate step. For example,
2985/// if you had a date of `2024-10-31` and wanted to change both the day
2986/// and the month, and each setting was validated independent of the other,
2987/// you would need to be careful to set the day first and then the month.
2988/// In some cases, you would need to set the month first and then the day!
2989///
2990/// But with the builder, you can set values in any order:
2991///
2992/// ```
2993/// use jiff::civil::date;
2994///
2995/// let d1 = date(2024, 10, 31);
2996/// let d2 = d1.with().month(11).day(30).build()?;
2997/// assert_eq!(d2, date(2024, 11, 30));
2998///
2999/// let d1 = date(2024, 4, 30);
3000/// let d2 = d1.with().day(31).month(7).build()?;
3001/// assert_eq!(d2, date(2024, 7, 31));
3002///
3003/// # Ok::<(), Box<dyn std::error::Error>>(())
3004/// ```
3005#[derive(Clone, Copy, Debug)]
3006pub struct DateWith {
3007    original: Date,
3008    year: Option<DateWithYear>,
3009    month: Option<i8>,
3010    day: Option<DateWithDay>,
3011}
3012
3013impl DateWith {
3014    #[inline]
3015    fn new(original: Date) -> DateWith {
3016        DateWith { original, year: None, month: None, day: None }
3017    }
3018
3019    /// Create a new `Date` from the fields set on this configuration.
3020    ///
3021    /// An error occurs when the fields combine to an invalid date.
3022    ///
3023    /// For any fields not set on this configuration, the values are taken from
3024    /// the [`Date`] that originally created this configuration. When no values
3025    /// are set, this routine is guaranteed to succeed and will always return
3026    /// the original date without modification.
3027    ///
3028    /// # Example
3029    ///
3030    /// This creates a date corresponding to the last day in the year:
3031    ///
3032    /// ```
3033    /// use jiff::civil::date;
3034    ///
3035    /// assert_eq!(
3036    ///     date(2023, 1, 1).with().day_of_year_no_leap(365).build()?,
3037    ///     date(2023, 12, 31),
3038    /// );
3039    /// // It also works with leap years for the same input:
3040    /// assert_eq!(
3041    ///     date(2024, 1, 1).with().day_of_year_no_leap(365).build()?,
3042    ///     date(2024, 12, 31),
3043    /// );
3044    ///
3045    /// # Ok::<(), Box<dyn std::error::Error>>(())
3046    /// ```
3047    ///
3048    /// # Example: error for invalid date
3049    ///
3050    /// If the fields combine to form an invalid date, then an error is
3051    /// returned:
3052    ///
3053    /// ```
3054    /// use jiff::civil::date;
3055    ///
3056    /// let d = date(2024, 11, 30);
3057    /// assert!(d.with().day(31).build().is_err());
3058    ///
3059    /// let d = date(2024, 2, 29);
3060    /// assert!(d.with().year(2023).build().is_err());
3061    /// ```
3062    #[inline]
3063    pub fn build(self) -> Result<Date, Error> {
3064        let year = match self.year {
3065            None => self.original.year(),
3066            Some(DateWithYear::Jiff(year)) => b::Year::check(year)?,
3067            Some(DateWithYear::EraYear(year, Era::CE)) => {
3068                b::YearCE::check(year)?
3069            }
3070            Some(DateWithYear::EraYear(year, Era::BCE)) => {
3071                let year_bce = b::YearBCE::check(year)?;
3072                -year_bce + 1
3073            }
3074        };
3075        let month = match self.month {
3076            None => self.original.month(),
3077            Some(month) => b::Month::check(month)?,
3078        };
3079        let day = match self.day {
3080            None => self.original.day(),
3081            Some(DateWithDay::OfMonth(day)) => b::Day::check(day)?,
3082            Some(DateWithDay::OfYear(day)) => {
3083                let idate = IDate::from_day_of_year(year, day)
3084                    .map_err(Error::itime_range)?;
3085                return Ok(Date::from_idate_const(idate));
3086            }
3087            Some(DateWithDay::OfYearNoLeap(day)) => {
3088                let idate = IDate::from_day_of_year_no_leap(year, day)
3089                    .map_err(Error::itime_range)?;
3090                return Ok(Date::from_idate_const(idate));
3091            }
3092        };
3093        Date::new(year, month, day)
3094    }
3095
3096    /// Set the year field on a [`Date`].
3097    ///
3098    /// One can access this value via [`Date::year`].
3099    ///
3100    /// This overrides any previous year settings.
3101    ///
3102    /// # Errors
3103    ///
3104    /// This returns an error when [`DateWith::build`] is called if the given
3105    /// year is outside the range `-9999..=9999`. This can also return an error
3106    /// if the resulting date is otherwise invalid.
3107    ///
3108    /// # Example
3109    ///
3110    /// This shows how to create a new date with a different year:
3111    ///
3112    /// ```
3113    /// use jiff::civil::date;
3114    ///
3115    /// let d1 = date(2005, 11, 5);
3116    /// assert_eq!(d1.year(), 2005);
3117    /// let d2 = d1.with().year(2007).build()?;
3118    /// assert_eq!(d2.year(), 2007);
3119    ///
3120    /// # Ok::<(), Box<dyn std::error::Error>>(())
3121    /// ```
3122    ///
3123    /// # Example: only changing the year can fail
3124    ///
3125    /// For example, while `2024-02-29` is valid, `2023-02-29` is not:
3126    ///
3127    /// ```
3128    /// use jiff::civil::date;
3129    ///
3130    /// let d1 = date(2024, 2, 29);
3131    /// assert!(d1.with().year(2023).build().is_err());
3132    /// ```
3133    #[inline]
3134    pub fn year(self, year: i16) -> DateWith {
3135        DateWith { year: Some(DateWithYear::Jiff(year)), ..self }
3136    }
3137
3138    /// Set year of a date via its era and its non-negative numeric component.
3139    ///
3140    /// One can access this value via [`Date::era_year`].
3141    ///
3142    /// # Errors
3143    ///
3144    /// This returns an error when [`DateWith::build`] is called if the year is
3145    /// outside the range for the era specified. For [`Era::BCE`], the range is
3146    /// `1..=10000`. For [`Era::CE`], the range is `1..=9999`.
3147    ///
3148    /// # Example
3149    ///
3150    /// This shows that `CE` years are equivalent to the years used by this
3151    /// crate:
3152    ///
3153    /// ```
3154    /// use jiff::civil::{Era, date};
3155    ///
3156    /// let d1 = date(2005, 11, 5);
3157    /// assert_eq!(d1.year(), 2005);
3158    /// let d2 = d1.with().era_year(2007, Era::CE).build()?;
3159    /// assert_eq!(d2.year(), 2007);
3160    ///
3161    /// // CE years are always positive and can be at most 9999:
3162    /// assert!(d1.with().era_year(-5, Era::CE).build().is_err());
3163    /// assert!(d1.with().era_year(10_000, Era::CE).build().is_err());
3164    ///
3165    /// # Ok::<(), Box<dyn std::error::Error>>(())
3166    /// ```
3167    ///
3168    /// But `BCE` years always correspond to years less than or equal to `0`
3169    /// in this crate:
3170    ///
3171    /// ```
3172    /// use jiff::civil::{Era, date};
3173    ///
3174    /// let d1 = date(-27, 7, 1);
3175    /// assert_eq!(d1.year(), -27);
3176    /// assert_eq!(d1.era_year(), (28, Era::BCE));
3177    ///
3178    /// let d2 = d1.with().era_year(509, Era::BCE).build()?;
3179    /// assert_eq!(d2.year(), -508);
3180    /// assert_eq!(d2.era_year(), (509, Era::BCE));
3181    ///
3182    /// let d2 = d1.with().era_year(10_000, Era::BCE).build()?;
3183    /// assert_eq!(d2.year(), -9_999);
3184    /// assert_eq!(d2.era_year(), (10_000, Era::BCE));
3185    ///
3186    /// // BCE years are always positive and can be at most 10000:
3187    /// assert!(d1.with().era_year(-5, Era::BCE).build().is_err());
3188    /// assert!(d1.with().era_year(10_001, Era::BCE).build().is_err());
3189    ///
3190    /// # Ok::<(), Box<dyn std::error::Error>>(())
3191    /// ```
3192    ///
3193    /// # Example: overrides `DateWith::year`
3194    ///
3195    /// Setting this option will override any previous `DateWith::year`
3196    /// option:
3197    ///
3198    /// ```
3199    /// use jiff::civil::{Era, date};
3200    ///
3201    /// let d1 = date(2024, 7, 2);
3202    /// let d2 = d1.with().year(2000).era_year(1900, Era::CE).build()?;
3203    /// assert_eq!(d2, date(1900, 7, 2));
3204    ///
3205    /// # Ok::<(), Box<dyn std::error::Error>>(())
3206    /// ```
3207    ///
3208    /// Similarly, `DateWith::year` will override any previous call to
3209    /// `DateWith::era_year`:
3210    ///
3211    /// ```
3212    /// use jiff::civil::{Era, date};
3213    ///
3214    /// let d1 = date(2024, 7, 2);
3215    /// let d2 = d1.with().era_year(1900, Era::CE).year(2000).build()?;
3216    /// assert_eq!(d2, date(2000, 7, 2));
3217    ///
3218    /// # Ok::<(), Box<dyn std::error::Error>>(())
3219    /// ```
3220    #[inline]
3221    pub fn era_year(self, year: i16, era: Era) -> DateWith {
3222        DateWith { year: Some(DateWithYear::EraYear(year, era)), ..self }
3223    }
3224
3225    /// Set the month field on a [`Date`].
3226    ///
3227    /// One can access this value via [`Date::month`].
3228    ///
3229    /// This overrides any previous month settings.
3230    ///
3231    /// # Errors
3232    ///
3233    /// This returns an error when [`DateWith::build`] is called if the given
3234    /// month is outside the range `1..=12`. This can also return an error if
3235    /// the resulting date is otherwise invalid.
3236    ///
3237    /// # Example
3238    ///
3239    /// This shows how to create a new date with a different month:
3240    ///
3241    /// ```
3242    /// use jiff::civil::date;
3243    ///
3244    /// let d1 = date(2005, 11, 5);
3245    /// assert_eq!(d1.month(), 11);
3246    /// let d2 = d1.with().month(6).build()?;
3247    /// assert_eq!(d2.month(), 6);
3248    ///
3249    /// # Ok::<(), Box<dyn std::error::Error>>(())
3250    /// ```
3251    ///
3252    /// # Example: only changing the month can fail
3253    ///
3254    /// For example, while `2024-10-31` is valid, `2024-11-31` is not:
3255    ///
3256    /// ```
3257    /// use jiff::civil::date;
3258    ///
3259    /// let d = date(2024, 10, 31);
3260    /// assert!(d.with().month(11).build().is_err());
3261    /// ```
3262    #[inline]
3263    pub fn month(self, month: i8) -> DateWith {
3264        DateWith { month: Some(month), ..self }
3265    }
3266
3267    /// Set the day field on a [`Date`].
3268    ///
3269    /// One can access this value via [`Date::day`].
3270    ///
3271    /// This overrides any previous day settings.
3272    ///
3273    /// # Errors
3274    ///
3275    /// This returns an error when [`DateWith::build`] is called if the given
3276    /// given day is outside of allowable days for the corresponding year and
3277    /// month fields.
3278    ///
3279    /// # Example
3280    ///
3281    /// This shows some examples of setting the day, including a leap day:
3282    ///
3283    /// ```
3284    /// use jiff::civil::date;
3285    ///
3286    /// let d1 = date(2024, 2, 5);
3287    /// assert_eq!(d1.day(), 5);
3288    /// let d2 = d1.with().day(10).build()?;
3289    /// assert_eq!(d2.day(), 10);
3290    /// let d3 = d1.with().day(29).build()?;
3291    /// assert_eq!(d3.day(), 29);
3292    ///
3293    /// # Ok::<(), Box<dyn std::error::Error>>(())
3294    /// ```
3295    ///
3296    /// # Example: changing only the day can fail
3297    ///
3298    /// This shows some examples that will fail:
3299    ///
3300    /// ```
3301    /// use jiff::civil::date;
3302    ///
3303    /// let d1 = date(2023, 2, 5);
3304    /// // 2023 is not a leap year
3305    /// assert!(d1.with().day(29).build().is_err());
3306    ///
3307    /// // September has 30 days, not 31.
3308    /// let d1 = date(2023, 9, 5);
3309    /// assert!(d1.with().day(31).build().is_err());
3310    /// ```
3311    #[inline]
3312    pub fn day(self, day: i8) -> DateWith {
3313        DateWith { day: Some(DateWithDay::OfMonth(day)), ..self }
3314    }
3315
3316    /// Set the day field on a [`Date`] via the ordinal number of a day within
3317    /// a year.
3318    ///
3319    /// When used, any settings for month are ignored since the month is
3320    /// determined by the day of the year.
3321    ///
3322    /// The valid values for `day` are `1..=366`. Note though that `366` is
3323    /// only valid for leap years.
3324    ///
3325    /// This overrides any previous day settings.
3326    ///
3327    /// # Errors
3328    ///
3329    /// This returns an error when [`DateWith::build`] is called if the given
3330    /// day is outside the allowed range of `1..=366`, or when a value of `366`
3331    /// is given for a non-leap year.
3332    ///
3333    /// # Example
3334    ///
3335    /// This demonstrates that if a year is a leap year, then `60` corresponds
3336    /// to February 29:
3337    ///
3338    /// ```
3339    /// use jiff::civil::date;
3340    ///
3341    /// let d = date(2024, 1, 1);
3342    /// assert_eq!(d.with().day_of_year(60).build()?, date(2024, 2, 29));
3343    ///
3344    /// # Ok::<(), Box<dyn std::error::Error>>(())
3345    /// ```
3346    ///
3347    /// But for non-leap years, day 60 is March 1:
3348    ///
3349    /// ```
3350    /// use jiff::civil::date;
3351    ///
3352    /// let d = date(2023, 1, 1);
3353    /// assert_eq!(d.with().day_of_year(60).build()?, date(2023, 3, 1));
3354    ///
3355    /// # Ok::<(), Box<dyn std::error::Error>>(())
3356    /// ```
3357    ///
3358    /// And using `366` for a non-leap year will result in an error, since
3359    /// non-leap years only have 365 days:
3360    ///
3361    /// ```
3362    /// use jiff::civil::date;
3363    ///
3364    /// let d = date(2023, 1, 1);
3365    /// assert!(d.with().day_of_year(366).build().is_err());
3366    /// // The maximal year is not a leap year, so it returns an error too.
3367    /// let d = date(9999, 1, 1);
3368    /// assert!(d.with().day_of_year(366).build().is_err());
3369    /// ```
3370    #[inline]
3371    pub fn day_of_year(self, day: i16) -> DateWith {
3372        DateWith { day: Some(DateWithDay::OfYear(day)), ..self }
3373    }
3374
3375    /// Set the day field on a [`Date`] via the ordinal number of a day within
3376    /// a year, but ignoring leap years.
3377    ///
3378    /// When used, any settings for month are ignored since the month is
3379    /// determined by the day of the year.
3380    ///
3381    /// The valid values for `day` are `1..=365`. The value `365` always
3382    /// corresponds to the last day of the year, even for leap years. It is
3383    /// impossible for this routine to return a date corresponding to February
3384    /// 29.
3385    ///
3386    /// This overrides any previous day settings.
3387    ///
3388    /// # Errors
3389    ///
3390    /// This returns an error when [`DateWith::build`] is called if the given
3391    /// day is outside the allowed range of `1..=365`.
3392    ///
3393    /// # Example
3394    ///
3395    /// This demonstrates that `60` corresponds to March 1, regardless of
3396    /// whether the year is a leap year or not:
3397    ///
3398    /// ```
3399    /// use jiff::civil::date;
3400    ///
3401    /// assert_eq!(
3402    ///     date(2023, 1, 1).with().day_of_year_no_leap(60).build()?,
3403    ///     date(2023, 3, 1),
3404    /// );
3405    ///
3406    /// assert_eq!(
3407    ///     date(2024, 1, 1).with().day_of_year_no_leap(60).build()?,
3408    ///     date(2024, 3, 1),
3409    /// );
3410    ///
3411    /// # Ok::<(), Box<dyn std::error::Error>>(())
3412    /// ```
3413    ///
3414    /// And using `365` for any year will always yield the last day of the
3415    /// year:
3416    ///
3417    /// ```
3418    /// use jiff::civil::date;
3419    ///
3420    /// let d = date(2023, 1, 1);
3421    /// assert_eq!(
3422    ///     d.with().day_of_year_no_leap(365).build()?,
3423    ///     d.last_of_year(),
3424    /// );
3425    ///
3426    /// let d = date(2024, 1, 1);
3427    /// assert_eq!(
3428    ///     d.with().day_of_year_no_leap(365).build()?,
3429    ///     d.last_of_year(),
3430    /// );
3431    ///
3432    /// let d = date(9999, 1, 1);
3433    /// assert_eq!(
3434    ///     d.with().day_of_year_no_leap(365).build()?,
3435    ///     d.last_of_year(),
3436    /// );
3437    ///
3438    /// # Ok::<(), Box<dyn std::error::Error>>(())
3439    /// ```
3440    ///
3441    /// A value of `366` is out of bounds, even for leap years:
3442    ///
3443    /// ```
3444    /// use jiff::civil::date;
3445    ///
3446    /// let d = date(2024, 1, 1);
3447    /// assert!(d.with().day_of_year_no_leap(366).build().is_err());
3448    /// ```
3449    #[inline]
3450    pub fn day_of_year_no_leap(self, day: i16) -> DateWith {
3451        DateWith { day: Some(DateWithDay::OfYearNoLeap(day)), ..self }
3452    }
3453}
3454
3455/// Encodes the "with year" option of [`DateWith`].
3456///
3457/// This encodes the invariant that `DateWith::year` and `DateWith::era_year`
3458/// are mutually exclusive and override each other.
3459#[derive(Clone, Copy, Debug)]
3460enum DateWithYear {
3461    Jiff(i16),
3462    EraYear(i16, Era),
3463}
3464
3465/// Encodes the "with day" option of [`DateWith`].
3466///
3467/// This encodes the invariant that `DateWith::day`, `DateWith::day_of_year`
3468/// and `DateWith::day_of_year_no_leap` are all mutually exclusive and override
3469/// each other.
3470///
3471/// Note that when "day of year" or "day of year no leap" are used, then if a
3472/// day of month is set, it is ignored.
3473#[derive(Clone, Copy, Debug)]
3474enum DateWithDay {
3475    OfMonth(i8),
3476    OfYear(i16),
3477    OfYearNoLeap(i16),
3478}
3479
3480/// Returns the Unix epoch day corresponding to the first day in the ISO 8601
3481/// week year given.
3482///
3483/// Ref: http://howardhinnant.github.io/date_algorithms.html
3484fn iso_week_start_from_year(year: i16) -> i32 {
3485    // A week's year always corresponds to the Gregorian year in which the
3486    // Thursday of that week falls. Therefore, Jan 4 is *always* in the first
3487    // week of any ISO week year.
3488    let date_in_first_week = Date::new_unchecked(year, 1, 4);
3489    // The start of the first week is a Monday, so find the number of days
3490    // since Monday from a date that we know is in the first ISO week of
3491    // `year`.
3492    let diff_from_monday = date_in_first_week.weekday().since(Weekday::Monday);
3493    date_in_first_week.to_unix_epoch_day() - i32::from(diff_from_monday)
3494}
3495
3496/// Adds or subtracts `sign` from the given `year`/`month`.
3497///
3498/// If month overflows in either direction, then the `year` returned is
3499/// adjusted as appropriate.
3500fn month_add_one(
3501    mut year: i16,
3502    mut month: i8,
3503    delta: b::Sign,
3504) -> Result<(i16, i8), Error> {
3505    month += delta.as_i8();
3506    if month < 1 {
3507        year -= 1;
3508        month += 12;
3509    } else if month > 12 {
3510        year += 1;
3511        month -= 12;
3512    }
3513    let year = b::Year::check(year)?;
3514    Ok((year, month))
3515}
3516
3517/// Adds the given span of months to the `month` given.
3518///
3519/// If adding (or subtracting) would result in overflowing the `month` value,
3520/// then the amount by which it overflowed, in units of years, is returned. For
3521/// example, adding 14 months to the month `3` (March) will result in returning
3522/// the month `5` (May) with `1` year of overflow.
3523///
3524/// # Preconditions
3525///
3526/// Callers must ensure that `span` is in bounds for `b::SpanMonths`.
3527fn month_add_overflowing(month: i8, span: i32) -> (i8, i16) {
3528    debug_assert!(b::SpanMonths::check(span).is_ok());
3529    let month = i32::from(month);
3530    let total = month - 1 + span;
3531    let years = total.div_euclid(12);
3532    let month = total.rem_euclid(12) + 1;
3533    // OK because `month` is derived from `% 12`, so must fit into an `i8`. And
3534    // becuase `years` is derived from `([1-12] - 1 + SpanMonths) / 12` where
3535    // the maximum `SpanMonths` is `239976`. Thus, the result is guaranteed to
3536    // fit into an `i16`.
3537    (month as i8, years as i16)
3538}
3539
3540#[cfg(test)]
3541mod tests {
3542    use std::io::Cursor;
3543
3544    use crate::{civil::date, span::span_eq, tz::TimeZone, Timestamp, ToSpan};
3545
3546    use super::*;
3547
3548    #[test]
3549    fn t_from_unix() {
3550        fn date_from_timestamp(timestamp: Timestamp) -> Date {
3551            timestamp.to_zoned(TimeZone::UTC).datetime().date()
3552        }
3553
3554        assert_eq!(
3555            date(1970, 1, 1),
3556            date_from_timestamp(Timestamp::new(0, 0).unwrap()),
3557        );
3558        assert_eq!(
3559            date(1969, 12, 31),
3560            date_from_timestamp(Timestamp::new(-1, 0).unwrap()),
3561        );
3562        assert_eq!(
3563            date(1969, 12, 31),
3564            date_from_timestamp(Timestamp::new(-86_400, 0).unwrap()),
3565        );
3566        assert_eq!(
3567            date(1969, 12, 30),
3568            date_from_timestamp(Timestamp::new(-86_401, 0).unwrap()),
3569        );
3570        assert_eq!(
3571            date(-9999, 1, 2),
3572            date_from_timestamp(
3573                Timestamp::new(b::UnixSeconds::MIN, 0).unwrap()
3574            ),
3575        );
3576        assert_eq!(
3577            date(9999, 12, 30),
3578            date_from_timestamp(
3579                Timestamp::new(b::UnixSeconds::MAX, 0).unwrap()
3580            ),
3581        );
3582    }
3583
3584    #[test]
3585    #[cfg(not(miri))]
3586    fn all_days_to_date_roundtrip() {
3587        for rd in -100_000..=100_000 {
3588            let date = Date::from_unix_epoch_day(rd);
3589            let got = date.to_unix_epoch_day();
3590            assert_eq!(rd, got, "for date {date:?}");
3591        }
3592    }
3593
3594    #[test]
3595    #[cfg(not(miri))]
3596    fn all_date_to_days_roundtrip() {
3597        let year_range = 2000..=2500;
3598        // let year_range = -9999..=9999;
3599        for year in year_range {
3600            for month in b::Month::MIN..=b::Month::MAX {
3601                for day in 1..=itime::days_in_month(year, month) {
3602                    let date = date(year, month, day);
3603                    let rd = date.to_unix_epoch_day();
3604                    let got = Date::from_unix_epoch_day(rd);
3605                    assert_eq!(date, got, "for date {date:?}");
3606                }
3607            }
3608        }
3609    }
3610
3611    #[test]
3612    #[cfg(not(miri))]
3613    fn all_date_to_iso_week_date_roundtrip() {
3614        let year_range = 2000..=2500;
3615        for year in year_range {
3616            for month in [1, 2, 4] {
3617                for day in 20..=itime::days_in_month(year, month) {
3618                    let date = date(year, month, day);
3619                    let wd = date.iso_week_date();
3620                    let got = wd.date();
3621                    assert_eq!(
3622                        date, got,
3623                        "for date {date:?}, and ISO week date {wd:?}"
3624                    );
3625                }
3626            }
3627        }
3628
3629        let year_range = -9999..=-9500;
3630        for year in year_range {
3631            for month in [1, 2, 4] {
3632                for day in 20..=itime::days_in_month(year, month) {
3633                    let date = date(year, month, day);
3634                    let wd = date.iso_week_date();
3635                    let got = wd.date();
3636                    assert_eq!(
3637                        date, got,
3638                        "for date {date:?}, and ISO week date {wd:?}"
3639                    );
3640                }
3641            }
3642        }
3643    }
3644
3645    #[test]
3646    fn add_constrained() {
3647        use crate::ToSpan;
3648
3649        let d1 = date(2023, 3, 31);
3650        let d2 = d1.checked_add(1.months().days(1)).unwrap();
3651        assert_eq!(d2, date(2023, 5, 1));
3652    }
3653
3654    #[test]
3655    fn since_years() {
3656        let d1 = date(2023, 4, 15);
3657        let d2 = date(2019, 2, 22);
3658        let span = d1.since((Unit::Year, d2)).unwrap();
3659        span_eq!(span, 4.years().months(1).days(21));
3660        let span = d2.since((Unit::Year, d1)).unwrap();
3661        span_eq!(span, -4.years().months(1).days(24));
3662
3663        let d1 = date(2023, 2, 22);
3664        let d2 = date(2019, 4, 15);
3665        let span = d1.since((Unit::Year, d2)).unwrap();
3666        span_eq!(span, 3.years().months(10).days(7));
3667        let span = d2.since((Unit::Year, d1)).unwrap();
3668        span_eq!(span, -3.years().months(10).days(7));
3669
3670        let d1 = date(9999, 12, 31);
3671        let d2 = date(-9999, 1, 1);
3672        let span = d1.since((Unit::Year, d2)).unwrap();
3673        span_eq!(span, 19998.years().months(11).days(30));
3674        let span = d2.since((Unit::Year, d1)).unwrap();
3675        span_eq!(span, -19998.years().months(11).days(30));
3676    }
3677
3678    #[test]
3679    fn since_months() {
3680        let d1 = date(2024, 7, 24);
3681        let d2 = date(2024, 2, 22);
3682        let span = d1.since((Unit::Month, d2)).unwrap();
3683        span_eq!(span, 5.months().days(2));
3684        let span = d2.since((Unit::Month, d1)).unwrap();
3685        span_eq!(span, -5.months().days(2));
3686        assert_eq!(d2, d1.checked_sub(5.months().days(2)).unwrap());
3687        assert_eq!(d1, d2.checked_sub(-5.months().days(2)).unwrap());
3688
3689        let d1 = date(2024, 7, 15);
3690        let d2 = date(2024, 2, 22);
3691        let span = d1.since((Unit::Month, d2)).unwrap();
3692        span_eq!(span, 4.months().days(22));
3693        let span = d2.since((Unit::Month, d1)).unwrap();
3694        span_eq!(span, -4.months().days(23));
3695        assert_eq!(d2, d1.checked_sub(4.months().days(22)).unwrap());
3696        assert_eq!(d1, d2.checked_sub(-4.months().days(23)).unwrap());
3697
3698        let d1 = date(2023, 4, 15);
3699        let d2 = date(2023, 2, 22);
3700        let span = d1.since((Unit::Month, d2)).unwrap();
3701        span_eq!(span, 1.month().days(21));
3702        let span = d2.since((Unit::Month, d1)).unwrap();
3703        span_eq!(span, -1.month().days(24));
3704        assert_eq!(d2, d1.checked_sub(1.month().days(21)).unwrap());
3705        assert_eq!(d1, d2.checked_sub(-1.month().days(24)).unwrap());
3706
3707        let d1 = date(2023, 4, 15);
3708        let d2 = date(2019, 2, 22);
3709        let span = d1.since((Unit::Month, d2)).unwrap();
3710        span_eq!(span, 49.months().days(21));
3711        let span = d2.since((Unit::Month, d1)).unwrap();
3712        span_eq!(span, -49.months().days(24));
3713    }
3714
3715    #[test]
3716    fn since_weeks() {
3717        let d1 = date(2024, 7, 15);
3718        let d2 = date(2024, 6, 22);
3719        let span = d1.since((Unit::Week, d2)).unwrap();
3720        span_eq!(span, 3.weeks().days(2));
3721        let span = d2.since((Unit::Week, d1)).unwrap();
3722        span_eq!(span, -3.weeks().days(2));
3723    }
3724
3725    #[test]
3726    fn since_days() {
3727        let d1 = date(2024, 7, 15);
3728        let d2 = date(2024, 2, 22);
3729        let span = d1.since((Unit::Day, d2)).unwrap();
3730        span_eq!(span, 144.days());
3731        let span = d2.since((Unit::Day, d1)).unwrap();
3732        span_eq!(span, -144.days());
3733    }
3734
3735    #[test]
3736    fn until_month_lengths() {
3737        let jan1 = date(2020, 1, 1);
3738        let feb1 = date(2020, 2, 1);
3739        let mar1 = date(2020, 3, 1);
3740
3741        span_eq!(jan1.until(feb1).unwrap(), 31.days());
3742        span_eq!(jan1.until((Unit::Month, feb1)).unwrap(), 1.month());
3743        span_eq!(feb1.until(mar1).unwrap(), 29.days());
3744        span_eq!(feb1.until((Unit::Month, mar1)).unwrap(), 1.month());
3745        span_eq!(jan1.until(mar1).unwrap(), 60.days());
3746        span_eq!(jan1.until((Unit::Month, mar1)).unwrap(), 2.months());
3747    }
3748
3749    // Ref: https://github.com/tc39/proposal-temporal/issues/2845#issuecomment-2121057896
3750    #[test]
3751    fn since_until_not_commutative() {
3752        // Temporal.PlainDate.from("2020-04-30").since("2020-02-29", {largestUnit: "months"})
3753        // // => P2M
3754        // Temporal.PlainDate.from("2020-02-29").until("2020-04-30", {largestUnit: "months"})
3755        // // => P2M1D
3756        let d1 = date(2020, 4, 30);
3757        let d2 = date(2020, 2, 29);
3758
3759        let since = d1.since((Unit::Month, d2)).unwrap();
3760        span_eq!(since, 2.months());
3761
3762        let until = d2.until((Unit::Month, d1)).unwrap();
3763        span_eq!(until, 2.months().days(1));
3764    }
3765
3766    // Ref: https://github.com/tc39/proposal-temporal/issues/2893
3767    #[test]
3768    fn until_weeks_round() {
3769        use crate::{RoundMode, SpanRound};
3770
3771        let earlier = date(2019, 1, 8);
3772        let later = date(2021, 9, 7);
3773        let span = earlier.until((Unit::Week, later)).unwrap();
3774        span_eq!(span, 139.weeks());
3775
3776        let options = SpanRound::new()
3777            .smallest(Unit::Week)
3778            .mode(RoundMode::HalfExpand)
3779            .relative(earlier.to_datetime(Time::midnight()));
3780        let rounded = span.round(options).unwrap();
3781        span_eq!(rounded, 139.weeks());
3782    }
3783
3784    // This test checks current behavior, but I think it's wrong. I think the
3785    // results below should be 11 months and 1 month.
3786    //
3787    // 2026-02-01: No, actually, the results here match what Temporal does:
3788    //
3789    // >> date = Temporal.PlainDate.from("2023-05-31")
3790    // >> date.until("2024-04-30", {largestUnit: 'month'}).toString()
3791    // "P10M30D"
3792    // >> date.until("2023-06-30", {largestUnit: 'month'}).toString()
3793    // "P30D"
3794    //
3795    // The specific reasoning here has to do with a trade-off where alternative
3796    // algorithms result in even less intuitive results. See 2535 linked below.
3797    //
3798    // Ref: https://github.com/tc39/proposal-temporal/issues/2919
3799    // Ref: https://github.com/tc39/proposal-temporal/issues/2535
3800    #[test]
3801    fn until_months_no_balance() {
3802        let sp =
3803            date(2023, 5, 31).until((Unit::Month, date(2024, 4, 30))).unwrap();
3804        span_eq!(sp, 10.months().days(30));
3805
3806        let sp =
3807            date(2023, 5, 31).until((Unit::Month, date(2023, 6, 30))).unwrap();
3808        span_eq!(sp, 30.days());
3809    }
3810
3811    #[test]
3812    fn until_extremes() {
3813        let d1 = date(-9999, 12, 1);
3814        let d2 = date(-9999, 1, 2);
3815        span_eq!(d1.until((Unit::Month, d2)).unwrap(), -10.months().days(30));
3816
3817        let d1 = date(9999, 1, 2);
3818        let d2 = date(9999, 12, 1);
3819        span_eq!(d1.until((Unit::Month, d2)).unwrap(), 10.months().days(29));
3820    }
3821
3822    #[test]
3823    fn test_month_add() {
3824        let add =
3825            |year: i16, month: i8, delta: i8| -> Result<(i16, i8), Error> {
3826                month_add_one(year, month, b::Sign::from(delta))
3827            };
3828
3829        assert_eq!(add(2024, 1, 1).unwrap(), (2024, 2));
3830        assert_eq!(add(2024, 1, -1).unwrap(), (2023, 12));
3831        assert_eq!(add(2024, 12, 1).unwrap(), (2025, 1));
3832        assert_eq!(add(9999, 12, -1).unwrap(), (9999, 11));
3833        assert_eq!(add(-9999, 1, 1).unwrap(), (-9999, 2));
3834
3835        assert!(add(9999, 12, 1).is_err());
3836        assert!(add(-9999, 1, -1).is_err());
3837    }
3838
3839    #[test]
3840    fn test_month_add_overflowing() {
3841        let month_add = |month, span| month_add_overflowing(month, span);
3842
3843        assert_eq!((1, 0), month_add(1, 0));
3844        assert_eq!((12, 0), month_add(1, 11));
3845        assert_eq!((1, 1), month_add(1, 12));
3846        assert_eq!((2, 1), month_add(1, 13));
3847        assert_eq!((9, 1), month_add(1, 20));
3848        assert_eq!((12, 19998), month_add(12, b::SpanMonths::MAX));
3849
3850        assert_eq!((12, -1), month_add(1, -1));
3851        assert_eq!((11, -1), month_add(1, -2));
3852        assert_eq!((1, -1), month_add(1, -12));
3853        assert_eq!((12, -2), month_add(1, -13));
3854    }
3855
3856    #[test]
3857    fn date_size() {
3858        #[cfg(debug_assertions)]
3859        {
3860            assert_eq!(4, core::mem::size_of::<Date>());
3861        }
3862        #[cfg(not(debug_assertions))]
3863        {
3864            assert_eq!(4, core::mem::size_of::<Date>());
3865        }
3866    }
3867
3868    #[cfg(not(miri))]
3869    quickcheck::quickcheck! {
3870        fn prop_checked_add_then_sub(
3871            d1: Date,
3872            span: Span
3873        ) -> quickcheck::TestResult {
3874            // Force our span to have no units greater than days.
3875            let span = if span.largest_unit() <= Unit::Day {
3876                span
3877            } else {
3878                let round = SpanRound::new().largest(Unit::Day).relative(d1);
3879                let Ok(span) = span.round(round) else {
3880                    return quickcheck::TestResult::discard();
3881                };
3882                span
3883            };
3884            let Ok(d2) = d1.checked_add(span) else {
3885                return quickcheck::TestResult::discard();
3886            };
3887            let got = d2.checked_sub(span).unwrap();
3888            quickcheck::TestResult::from_bool(d1 == got)
3889        }
3890
3891        fn prop_checked_sub_then_add(
3892            d1: Date,
3893            span: Span
3894        ) -> quickcheck::TestResult {
3895            // Force our span to have no units greater than days.
3896            let span = if span.largest_unit() <= Unit::Day {
3897                span
3898            } else {
3899                let round = SpanRound::new().largest(Unit::Day).relative(d1);
3900                let Ok(span) = span.round(round) else {
3901                    return quickcheck::TestResult::discard();
3902                };
3903                span
3904            };
3905            let Ok(d2) = d1.checked_sub(span) else {
3906                return quickcheck::TestResult::discard();
3907            };
3908            let got = d2.checked_add(span).unwrap();
3909            quickcheck::TestResult::from_bool(d1 == got)
3910        }
3911
3912        fn prop_since_then_add(d1: Date, d2: Date) -> bool {
3913            let span = d1.since(d2).unwrap();
3914            let got = d2.checked_add(span).unwrap();
3915            d1 == got
3916        }
3917
3918        fn prop_until_then_sub(d1: Date, d2: Date) -> bool {
3919            let span = d1.until(d2).unwrap();
3920            let got = d2.checked_sub(span).unwrap();
3921            d1 == got
3922        }
3923    }
3924
3925    /// # `serde` deserializer compatibility test
3926    ///
3927    /// Serde YAML used to be unable to deserialize `jiff` types,
3928    /// as deserializing from bytes is not supported by the deserializer.
3929    ///
3930    /// - <https://github.com/BurntSushi/jiff/issues/138>
3931    /// - <https://github.com/BurntSushi/jiff/discussions/148>
3932    #[test]
3933    fn civil_date_deserialize_yaml() {
3934        let expected = date(2024, 10, 31);
3935
3936        let deserialized: Date = serde_yaml::from_str("2024-10-31").unwrap();
3937
3938        assert_eq!(deserialized, expected);
3939
3940        let deserialized: Date =
3941            serde_yaml::from_slice("2024-10-31".as_bytes()).unwrap();
3942
3943        assert_eq!(deserialized, expected);
3944
3945        let cursor = Cursor::new(b"2024-10-31");
3946        let deserialized: Date = serde_yaml::from_reader(cursor).unwrap();
3947
3948        assert_eq!(deserialized, expected);
3949    }
3950
3951    /// Regression test where converting to `IDate` and back to do the
3952    /// calculation was FUBAR.
3953    #[test]
3954    fn nth_weekday_of_month() {
3955        let d1 = date(1998, 1, 1);
3956        let d2 = d1.nth_weekday_of_month(5, Weekday::Saturday).unwrap();
3957        assert_eq!(d2, date(1998, 1, 31));
3958    }
3959
3960    /// Tests some extreme values for `Date::nth_weekday`.
3961    #[test]
3962    fn nth_weekday_extreme() {
3963        let weeks = 1043497;
3964
3965        let d1 = date(-9999, 1, 1);
3966        let d2 = d1.nth_weekday(weeks, Weekday::Monday).unwrap();
3967        assert_eq!(d2, date(9999, 12, 27));
3968        assert!(d1.nth_weekday(weeks + 1, Weekday::Monday).is_err());
3969
3970        let d1 = date(9999, 12, 31);
3971        let d2 = d1.nth_weekday(-weeks, Weekday::Friday).unwrap();
3972        assert_eq!(d2, date(-9999, 1, 5));
3973        assert!(d1.nth_weekday(weeks - 1, Weekday::Friday).is_err());
3974    }
3975}