jiff/civil/
date.rs

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