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