Coverage Report

Created: 2026-07-14 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jiff-0.2.31/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
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
134
pub enum Era {
135
    /// The "before common era" era.
136
    ///
137
    /// This corresponds to all years less than or equal to `0`.
138
    ///
139
    /// This is precisely equivalent to the "BC" or "before Christ" era.
140
    BCE,
141
    /// The "common era" era.
142
    ///
143
    /// This corresponds to all years greater than `0`.
144
    ///
145
    /// This is precisely equivalent to the "AD" or "anno Domini" or "in the
146
    /// year of the Lord" era.
147
    CE,
148
}
149
150
/// Creates a new `DateTime` value in a `const` context.
151
///
152
/// This is a convenience free function for [`DateTime::constant`]. It is
153
/// intended to provide a terse syntax for constructing `DateTime` values from
154
/// parameters that are known to be valid.
155
///
156
/// # Panics
157
///
158
/// This routine panics when [`DateTime::new`] would return an error. That
159
/// is, when the given components do not correspond to a valid datetime.
160
/// Namely, all of the following must be true:
161
///
162
/// * The year must be in the range `-9999..=9999`.
163
/// * The month must be in the range `1..=12`.
164
/// * The day must be at least `1` and must be at most the number of days
165
/// in the corresponding month. So for example, `2024-02-29` is valid but
166
/// `2023-02-29` is not.
167
/// * `0 <= hour <= 23`
168
/// * `0 <= minute <= 59`
169
/// * `0 <= second <= 59`
170
/// * `0 <= subsec_nanosecond <= 999,999,999`
171
///
172
/// Similarly, when used in a const context, invalid parameters will prevent
173
/// your Rust program from compiling.
174
///
175
/// # Example
176
///
177
/// ```
178
/// use jiff::civil::DateTime;
179
///
180
/// let d = DateTime::constant(2024, 2, 29, 21, 30, 5, 123_456_789);
181
/// assert_eq!(d.date().year(), 2024);
182
/// assert_eq!(d.date().month(), 2);
183
/// assert_eq!(d.date().day(), 29);
184
/// assert_eq!(d.time().hour(), 21);
185
/// assert_eq!(d.time().minute(), 30);
186
/// assert_eq!(d.time().second(), 5);
187
/// assert_eq!(d.time().millisecond(), 123);
188
/// assert_eq!(d.time().microsecond(), 456);
189
/// assert_eq!(d.time().nanosecond(), 789);
190
/// ```
191
#[inline]
192
0
pub const fn datetime(
193
0
    year: i16,
194
0
    month: i8,
195
0
    day: i8,
196
0
    hour: i8,
197
0
    minute: i8,
198
0
    second: i8,
199
0
    subsec_nanosecond: i32,
200
0
) -> DateTime {
201
0
    DateTime::constant(
202
0
        year,
203
0
        month,
204
0
        day,
205
0
        hour,
206
0
        minute,
207
0
        second,
208
0
        subsec_nanosecond,
209
    )
210
0
}
211
212
/// Creates a new `Date` value in a `const` context.
213
///
214
/// This is a convenience free function for [`Date::constant`]. It is intended
215
/// to provide a terse syntax for constructing `Date` values from parameters
216
/// that are known to be valid.
217
///
218
/// # Panics
219
///
220
/// This routine panics when [`Date::new`] would return an error. That is,
221
/// when the given year-month-day does not correspond to a valid date.
222
/// Namely, all of the following must be true:
223
///
224
/// * The year must be in the range `-9999..=9999`.
225
/// * The month must be in the range `1..=12`.
226
/// * The day must be at least `1` and must be at most the number of days
227
/// in the corresponding month. So for example, `2024-02-29` is valid but
228
/// `2023-02-29` is not.
229
///
230
/// Similarly, when used in a const context, invalid parameters will prevent
231
/// your Rust program from compiling.
232
///
233
/// # Example
234
///
235
/// ```
236
/// use jiff::civil::date;
237
///
238
/// let d = date(2024, 2, 29);
239
/// assert_eq!(d.year(), 2024);
240
/// assert_eq!(d.month(), 2);
241
/// assert_eq!(d.day(), 29);
242
/// ```
243
#[inline]
244
0
pub const fn date(year: i16, month: i8, day: i8) -> Date {
245
0
    Date::constant(year, month, day)
246
0
}
247
248
/// Creates a new `Time` value in a `const` context.
249
///
250
/// This is a convenience free function for [`Time::constant`]. It is intended
251
/// to provide a terse syntax for constructing `Time` values from parameters
252
/// that are known to be valid.
253
///
254
/// # Panics
255
///
256
/// This panics if the given values do not correspond to a valid `Time`.
257
/// All of the following conditions must be true:
258
///
259
/// * `0 <= hour <= 23`
260
/// * `0 <= minute <= 59`
261
/// * `0 <= second <= 59`
262
/// * `0 <= subsec_nanosecond <= 999,999,999`
263
///
264
/// Similarly, when used in a const context, invalid parameters will
265
/// prevent your Rust program from compiling.
266
///
267
/// # Example
268
///
269
/// This shows an example of a valid time in a `const` context:
270
///
271
/// ```
272
/// use jiff::civil::Time;
273
///
274
/// const BEDTIME: Time = Time::constant(21, 30, 5, 123_456_789);
275
/// assert_eq!(BEDTIME.hour(), 21);
276
/// assert_eq!(BEDTIME.minute(), 30);
277
/// assert_eq!(BEDTIME.second(), 5);
278
/// assert_eq!(BEDTIME.millisecond(), 123);
279
/// assert_eq!(BEDTIME.microsecond(), 456);
280
/// assert_eq!(BEDTIME.nanosecond(), 789);
281
/// assert_eq!(BEDTIME.subsec_nanosecond(), 123_456_789);
282
/// ```
283
#[inline]
284
0
pub const fn time(
285
0
    hour: i8,
286
0
    minute: i8,
287
0
    second: i8,
288
0
    subsec_nanosecond: i32,
289
0
) -> Time {
290
0
    Time::constant(hour, minute, second, subsec_nanosecond)
291
0
}