Coverage Report

Created: 2025-09-27 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}