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