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