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