Skip to main content

jiff/civil/
date.rs

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