/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jiff-0.2.15/src/civil/mod.rs
Line | Count | Source |
1 | | /*! |
2 | | Facilities for dealing with inexact dates and times. |
3 | | |
4 | | # Overview |
5 | | |
6 | | The essential types in this module are: |
7 | | |
8 | | * [`Date`] is a specific day in the Gregorian calendar. |
9 | | * [`Time`] is a specific wall clock time. |
10 | | * [`DateTime`] is a combination of a day and a time. |
11 | | |
12 | | Moreover, the [`date`](date()) and [`time`](time()) free functions can be used |
13 | | to conveniently create values of any of three types above: |
14 | | |
15 | | ``` |
16 | | use jiff::civil::{date, time}; |
17 | | |
18 | | assert_eq!(date(2024, 7, 31).to_string(), "2024-07-31"); |
19 | | assert_eq!(time(15, 20, 0, 123).to_string(), "15:20:00.000000123"); |
20 | | assert_eq!( |
21 | | date(2024, 7, 31).at(15, 20, 0, 123).to_string(), |
22 | | "2024-07-31T15:20:00.000000123", |
23 | | ); |
24 | | assert_eq!( |
25 | | time(15, 20, 0, 123).on(2024, 7, 31).to_string(), |
26 | | "2024-07-31T15:20:00.000000123", |
27 | | ); |
28 | | ``` |
29 | | |
30 | | # What is "civil" time? |
31 | | |
32 | | A civil datetime is a calendar date and a clock time. It also goes by the |
33 | | names "naive," "local" or "plain." The most important thing to understand |
34 | | about civil time is that it does not correspond to a precise instant in |
35 | | time. This is in contrast to types like [`Timestamp`](crate::Timestamp) and |
36 | | [`Zoned`](crate::Zoned), which _do_ correspond to a precise instant in time (to |
37 | | nanosecond precision). |
38 | | |
39 | | Because a civil datetime _never_ has a time zone associated with it, and |
40 | | because some time zones have transitions that skip or repeat clock times, it |
41 | | follows that not all civil datetimes precisely map to a single instant in time. |
42 | | For example, `2024-03-10 02:30` never existed on a clock in `America/New_York` |
43 | | because the 2 o'clock hour was skipped when the clocks were "moved forward" |
44 | | for daylight saving time. Conversely, `2024-11-03 01:30` occurred twice in |
45 | | `America/New_York` because the 1 o'clock hour was repeated when clocks were |
46 | | "moved backward" for daylight saving time. (When time is skipped, it's called a |
47 | | "gap." When time is repeated, it's called a "fold.") |
48 | | |
49 | | In contrast, an instant in time (that is, `Timestamp` or `Zoned`) can _always_ |
50 | | be converted to a civil datetime. And, when a civil datetime is combined |
51 | | with its time zone identifier _and_ its offset, the resulting machine readable |
52 | | string is unambiguous 100% of the time: |
53 | | |
54 | | ``` |
55 | | use jiff::{civil::date, tz::TimeZone}; |
56 | | |
57 | | let tz = TimeZone::get("America/New_York")?; |
58 | | let dt = date(2024, 11, 3).at(1, 30, 0, 0); |
59 | | // It's ambiguous, so asking for an unambiguous instant presents an error! |
60 | | assert!(tz.to_ambiguous_zoned(dt).unambiguous().is_err()); |
61 | | // Gives you the earlier time in a fold, i.e., before DST ends: |
62 | | assert_eq!( |
63 | | tz.to_ambiguous_zoned(dt).earlier()?.to_string(), |
64 | | "2024-11-03T01:30:00-04:00[America/New_York]", |
65 | | ); |
66 | | // Gives you the later time in a fold, i.e., after DST ends. |
67 | | // Notice the offset change from the previous example! |
68 | | assert_eq!( |
69 | | tz.to_ambiguous_zoned(dt).later()?.to_string(), |
70 | | "2024-11-03T01:30:00-05:00[America/New_York]", |
71 | | ); |
72 | | // "Just give me something reasonable" |
73 | | assert_eq!( |
74 | | tz.to_ambiguous_zoned(dt).compatible()?.to_string(), |
75 | | "2024-11-03T01:30:00-04:00[America/New_York]", |
76 | | ); |
77 | | |
78 | | # Ok::<(), Box<dyn std::error::Error>>(()) |
79 | | ``` |
80 | | |
81 | | # When should I use civil time? |
82 | | |
83 | | Here is a likely non-exhaustive list of reasons why you might want to use |
84 | | civil time: |
85 | | |
86 | | * When you want or need to deal with calendar and clock units as an |
87 | | intermediate step before and/or after associating it with a time zone. For |
88 | | example, perhaps you need to parse strings like `2000-01-01T00:00:00` from a |
89 | | CSV file that have no time zone or offset information, but the time zone is |
90 | | implied through some out-of-band mechanism. |
91 | | * When time zone is actually irrelevant. For example, a fitness tracking app |
92 | | that reminds you to work-out at 6am local time, regardless of which time zone |
93 | | you're in. |
94 | | * When you need to perform arithmetic that deliberately ignores daylight |
95 | | saving time. |
96 | | * When interacting with legacy systems or systems that specifically do not |
97 | | support time zones. |
98 | | */ |
99 | | |
100 | | pub use self::{ |
101 | | date::{Date, DateArithmetic, DateDifference, DateSeries, DateWith}, |
102 | | datetime::{ |
103 | | DateTime, DateTimeArithmetic, DateTimeDifference, DateTimeRound, |
104 | | DateTimeSeries, DateTimeWith, |
105 | | }, |
106 | | iso_week_date::ISOWeekDate, |
107 | | time::{ |
108 | | Time, TimeArithmetic, TimeDifference, TimeRound, TimeSeries, TimeWith, |
109 | | }, |
110 | | weekday::{Weekday, WeekdaysForward, WeekdaysReverse}, |
111 | | }; |
112 | | |
113 | | mod date; |
114 | | mod datetime; |
115 | | mod iso_week_date; |
116 | | mod time; |
117 | | mod weekday; |
118 | | |
119 | | /// The era corresponding to a particular year. |
120 | | /// |
121 | | /// The BCE era corresponds to years less than or equal to `0`, while the CE |
122 | | /// era corresponds to years greater than `0`. |
123 | | /// |
124 | | /// In particular, this crate allows years to be negative and also to be `0`, |
125 | | /// which is contrary to the common practice of excluding the year `0` when |
126 | | /// writing dates for the Gregorian calendar. Moreover, common practice eschews |
127 | | /// negative years in favor of labeling a year with an era notation. That is, |
128 | | /// the year `1 BCE` is year `0` in this crate. The year `2 BCE` is the year |
129 | | /// `-1` in this crate. |
130 | | /// |
131 | | /// To get the year in its era format, use [`Date::era_year`]. |
132 | | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
133 | | pub enum Era { |
134 | | /// The "before common era" era. |
135 | | /// |
136 | | /// This corresponds to all years less than or equal to `0`. |
137 | | /// |
138 | | /// This is precisely equivalent to the "BC" or "before Christ" era. |
139 | | BCE, |
140 | | /// The "common era" era. |
141 | | /// |
142 | | /// This corresponds to all years greater than `0`. |
143 | | /// |
144 | | /// This is precisely equivalent to the "AD" or "anno Domini" or "in the |
145 | | /// year of the Lord" era. |
146 | | CE, |
147 | | } |
148 | | |
149 | | /// Creates a new `DateTime` value in a `const` context. |
150 | | /// |
151 | | /// This is a convenience free function for [`DateTime::constant`]. It is |
152 | | /// intended to provide a terse syntax for constructing `DateTime` values from |
153 | | /// parameters that are known to be valid. |
154 | | /// |
155 | | /// # Panics |
156 | | /// |
157 | | /// This routine panics when [`DateTime::new`] would return an error. That |
158 | | /// is, when the given components do not correspond to a valid datetime. |
159 | | /// Namely, all of the following must be true: |
160 | | /// |
161 | | /// * The year must be in the range `-9999..=9999`. |
162 | | /// * The month must be in the range `1..=12`. |
163 | | /// * The day must be at least `1` and must be at most the number of days |
164 | | /// in the corresponding month. So for example, `2024-02-29` is valid but |
165 | | /// `2023-02-29` is not. |
166 | | /// * `0 <= hour <= 23` |
167 | | /// * `0 <= minute <= 59` |
168 | | /// * `0 <= second <= 59` |
169 | | /// * `0 <= subsec_nanosecond <= 999,999,999` |
170 | | /// |
171 | | /// Similarly, when used in a const context, invalid parameters will prevent |
172 | | /// your Rust program from compiling. |
173 | | /// |
174 | | /// # Example |
175 | | /// |
176 | | /// ``` |
177 | | /// use jiff::civil::DateTime; |
178 | | /// |
179 | | /// let d = DateTime::constant(2024, 2, 29, 21, 30, 5, 123_456_789); |
180 | | /// assert_eq!(d.date().year(), 2024); |
181 | | /// assert_eq!(d.date().month(), 2); |
182 | | /// assert_eq!(d.date().day(), 29); |
183 | | /// assert_eq!(d.time().hour(), 21); |
184 | | /// assert_eq!(d.time().minute(), 30); |
185 | | /// assert_eq!(d.time().second(), 5); |
186 | | /// assert_eq!(d.time().millisecond(), 123); |
187 | | /// assert_eq!(d.time().microsecond(), 456); |
188 | | /// assert_eq!(d.time().nanosecond(), 789); |
189 | | /// ``` |
190 | | #[inline] |
191 | 0 | pub const fn datetime( |
192 | 0 | year: i16, |
193 | 0 | month: i8, |
194 | 0 | day: i8, |
195 | 0 | hour: i8, |
196 | 0 | minute: i8, |
197 | 0 | second: i8, |
198 | 0 | subsec_nanosecond: i32, |
199 | 0 | ) -> DateTime { |
200 | 0 | DateTime::constant( |
201 | 0 | year, |
202 | 0 | month, |
203 | 0 | day, |
204 | 0 | hour, |
205 | 0 | minute, |
206 | 0 | second, |
207 | 0 | subsec_nanosecond, |
208 | | ) |
209 | 0 | } |
210 | | |
211 | | /// Creates a new `Date` value in a `const` context. |
212 | | /// |
213 | | /// This is a convenience free function for [`Date::constant`]. It is intended |
214 | | /// to provide a terse syntax for constructing `Date` values from parameters |
215 | | /// that are known to be valid. |
216 | | /// |
217 | | /// # Panics |
218 | | /// |
219 | | /// This routine panics when [`Date::new`] would return an error. That is, |
220 | | /// when the given year-month-day does not correspond to a valid date. |
221 | | /// Namely, all of the following must be true: |
222 | | /// |
223 | | /// * The year must be in the range `-9999..=9999`. |
224 | | /// * The month must be in the range `1..=12`. |
225 | | /// * The day must be at least `1` and must be at most the number of days |
226 | | /// in the corresponding month. So for example, `2024-02-29` is valid but |
227 | | /// `2023-02-29` is not. |
228 | | /// |
229 | | /// Similarly, when used in a const context, invalid parameters will prevent |
230 | | /// your Rust program from compiling. |
231 | | /// |
232 | | /// # Example |
233 | | /// |
234 | | /// ``` |
235 | | /// use jiff::civil::date; |
236 | | /// |
237 | | /// let d = date(2024, 2, 29); |
238 | | /// assert_eq!(d.year(), 2024); |
239 | | /// assert_eq!(d.month(), 2); |
240 | | /// assert_eq!(d.day(), 29); |
241 | | /// ``` |
242 | | #[inline] |
243 | 0 | pub const fn date(year: i16, month: i8, day: i8) -> Date { |
244 | 0 | Date::constant(year, month, day) |
245 | 0 | } |
246 | | |
247 | | /// Creates a new `Time` value in a `const` context. |
248 | | /// |
249 | | /// This is a convenience free function for [`Time::constant`]. It is intended |
250 | | /// to provide a terse syntax for constructing `Time` values from parameters |
251 | | /// that are known to be valid. |
252 | | /// |
253 | | /// # Panics |
254 | | /// |
255 | | /// This panics if the given values do not correspond to a valid `Time`. |
256 | | /// All of the following conditions must be true: |
257 | | /// |
258 | | /// * `0 <= hour <= 23` |
259 | | /// * `0 <= minute <= 59` |
260 | | /// * `0 <= second <= 59` |
261 | | /// * `0 <= subsec_nanosecond <= 999,999,999` |
262 | | /// |
263 | | /// Similarly, when used in a const context, invalid parameters will |
264 | | /// prevent your Rust program from compiling. |
265 | | /// |
266 | | /// # Example |
267 | | /// |
268 | | /// This shows an example of a valid time in a `const` context: |
269 | | /// |
270 | | /// ``` |
271 | | /// use jiff::civil::Time; |
272 | | /// |
273 | | /// const BEDTIME: Time = Time::constant(21, 30, 5, 123_456_789); |
274 | | /// assert_eq!(BEDTIME.hour(), 21); |
275 | | /// assert_eq!(BEDTIME.minute(), 30); |
276 | | /// assert_eq!(BEDTIME.second(), 5); |
277 | | /// assert_eq!(BEDTIME.millisecond(), 123); |
278 | | /// assert_eq!(BEDTIME.microsecond(), 456); |
279 | | /// assert_eq!(BEDTIME.nanosecond(), 789); |
280 | | /// assert_eq!(BEDTIME.subsec_nanosecond(), 123_456_789); |
281 | | /// ``` |
282 | | #[inline] |
283 | 0 | pub const fn time( |
284 | 0 | hour: i8, |
285 | 0 | minute: i8, |
286 | 0 | second: i8, |
287 | 0 | subsec_nanosecond: i32, |
288 | 0 | ) -> Time { |
289 | 0 | Time::constant(hour, minute, second, subsec_nanosecond) |
290 | 0 | } |