| 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 | pub const fn datetime( |
| 192 | year: i16, |
| 193 | month: i8, |
| 194 | day: i8, |
| 195 | hour: i8, |
| 196 | minute: i8, |
| 197 | second: i8, |
| 198 | subsec_nanosecond: i32, |
| 199 | ) -> DateTime { |
| 200 | DateTime::constant( |
| 201 | year, |
| 202 | month, |
| 203 | day, |
| 204 | hour, |
| 205 | minute, |
| 206 | second, |
| 207 | subsec_nanosecond, |
| 208 | ) |
| 209 | } |
| 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 | pub const fn date(year: i16, month: i8, day: i8) -> Date { |
| 244 | Date::constant(year, month, day) |
| 245 | } |
| 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 | pub const fn time( |
| 284 | hour: i8, |
| 285 | minute: i8, |
| 286 | second: i8, |
| 287 | subsec_nanosecond: i32, |
| 288 | ) -> Time { |
| 289 | Time::constant(hour, minute, second, subsec_nanosecond) |
| 290 | } |
| 291 | |