jiff/civil/
date.rs

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