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