Coverage Report

Created: 2025-10-31 06:57

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