icu_calendar/
duration.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use crate::Calendar;
6use core::fmt;
7use core::marker::PhantomData;
8
9/// A duration between two dates
10///
11/// Can be used to perform date arithmetic
12///
13/// # Example
14///
15/// ```rust
16/// use icu::calendar::{
17///     types::IsoWeekday, Date, DateDuration, DateDurationUnit,
18/// };
19///
20/// // Creating ISO date: 1992-09-02.
21/// let mut date_iso = Date::try_new_iso_date(1992, 9, 2)
22///     .expect("Failed to initialize ISO Date instance.");
23///
24/// assert_eq!(date_iso.day_of_week(), IsoWeekday::Wednesday);
25/// assert_eq!(date_iso.year().number, 1992);
26/// assert_eq!(date_iso.month().ordinal, 9);
27/// assert_eq!(date_iso.day_of_month().0, 2);
28///
29/// // Answering questions about days in month and year.
30/// assert_eq!(date_iso.days_in_year(), 366);
31/// assert_eq!(date_iso.days_in_month(), 30);
32///
33/// // Advancing date in-place by 1 year, 2 months, 3 weeks, 4 days.
34/// date_iso.add(DateDuration::new(1, 2, 3, 4));
35/// assert_eq!(date_iso.year().number, 1993);
36/// assert_eq!(date_iso.month().ordinal, 11);
37/// assert_eq!(date_iso.day_of_month().0, 27);
38///
39/// // Reverse date advancement.
40/// date_iso.add(DateDuration::new(-1, -2, -3, -4));
41/// assert_eq!(date_iso.year().number, 1992);
42/// assert_eq!(date_iso.month().ordinal, 9);
43/// assert_eq!(date_iso.day_of_month().0, 2);
44///
45/// // Creating ISO date: 2022-01-30.
46/// let newer_date_iso = Date::try_new_iso_date(2022, 1, 30)
47///     .expect("Failed to initialize ISO Date instance.");
48///
49/// // Comparing dates: 2022-01-30 and 1992-09-02.
50/// let duration = newer_date_iso.until(
51///     &date_iso,
52///     DateDurationUnit::Years,
53///     DateDurationUnit::Days,
54/// );
55/// assert_eq!(duration.years, 30);
56/// assert_eq!(duration.months, -8);
57/// assert_eq!(duration.days, 28);
58///
59/// // Create new date with date advancement. Reassign to new variable.
60/// let mutated_date_iso = date_iso.added(DateDuration::new(1, 2, 3, 4));
61/// assert_eq!(mutated_date_iso.year().number, 1993);
62/// assert_eq!(mutated_date_iso.month().ordinal, 11);
63/// assert_eq!(mutated_date_iso.day_of_month().0, 27);
64/// ```
65///
66/// Currently unstable for ICU4X 1.0
67#[derive(Eq, PartialEq)]
68#[allow(clippy::exhaustive_structs)] // this type should be stable (and is intended to be constructed manually)
69#[doc(hidden)]
70pub struct DateDuration<C: Calendar + ?Sized> {
71    /// The number of years
72    pub years: i32,
73    /// The number of months
74    pub months: i32,
75    /// The number of weeks
76    pub weeks: i32,
77    /// The number of days
78    pub days: i32,
79    /// A marker for the calendar
80    pub marker: PhantomData<C>,
81}
82
83// Custom impl so that C need not be bound on Copy/Clone
84impl<C: Calendar + ?Sized> Clone for DateDuration<C> {
85    fn clone(&self) -> Self {
86        *self
87    }
88}
89
90// Custom impl so that C need not be bound on Copy/Clone
91impl<C: Calendar + ?Sized> Copy for DateDuration<C> {}
92
93/// A "duration unit" used to specify the minimum or maximum duration of time to
94/// care about
95///
96/// Currently unstable for ICU4X 1.0
97#[derive(Copy, Clone, Eq, PartialEq, Debug)]
98#[allow(clippy::exhaustive_enums)] // this type should be stable
99#[doc(hidden)]
100pub enum DateDurationUnit {
101    /// Duration in years
102    Years,
103    /// Duration in months
104    Months,
105    /// Duration in weeks
106    Weeks,
107    /// Duration in days
108    Days,
109}
110
111impl<C: Calendar + ?Sized> Default for DateDuration<C> {
112    fn default() -> Self {
113        Self {
114            years: 0,
115            months: 0,
116            weeks: 0,
117            days: 0,
118            marker: PhantomData,
119        }
120    }
121}
122
123impl<C: Calendar + ?Sized> DateDuration<C> {
124    /// Construct a DateDuration
125    ///
126    /// ```rust
127    /// # use icu::calendar::*;
128    /// // two years, three months, and five days
129    /// let duration: DateDuration<Iso> = DateDuration::new(2, 3, 0, 5);
130    /// ```
131    pub fn new(years: i32, months: i32, weeks: i32, days: i32) -> Self {
132        DateDuration {
133            years,
134            months,
135            weeks,
136            days,
137            marker: PhantomData,
138        }
139    }
140
141    /// Explicitly cast duration to one for a different calendar
142    pub fn cast_unit<C2: Calendar + ?Sized>(self) -> DateDuration<C2> {
143        DateDuration {
144            years: self.years,
145            months: self.months,
146            days: self.days,
147            weeks: self.weeks,
148            marker: PhantomData,
149        }
150    }
151}
152
153impl<C: Calendar> fmt::Debug for DateDuration<C> {
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
155        f.debug_struct("DateDuration")
156            .field("years", &self.years)
157            .field("months", &self.months)
158            .field("weeks", &self.weeks)
159            .field("days", &self.days)
160            .finish()
161    }
162}