Merge branch '0.4.x' into main

This commit is contained in:
Paul Dicker 2023-05-11 17:28:07 +02:00
commit 7926f011be
32 changed files with 506 additions and 305 deletions

View File

@ -32,9 +32,8 @@ jobs:
- run: cargo test --doc --all-features --color=always -- --color=always - run: cargo test --doc --all-features --color=always -- --color=always
# later this may be able to be included with the below # later this may be able to be included with the below
# kept seperate for now as the following don't compile on 1.38.0 # kept separate for now as the following don't compile on 1.56.1
# * rkyv # * arbitrary
# * criterion
rust_msrv: rust_msrv:
strategy: strategy:
matrix: matrix:
@ -44,7 +43,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master - uses: dtolnay/rust-toolchain@master
with: with:
toolchain: 1.48.0 toolchain: 1.56.1
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
# run --lib and --doc to avoid the long running integration tests which are run elsewhere # run --lib and --doc to avoid the long running integration tests which are run elsewhere
- run: cargo test --lib --features unstable-locales,wasmbind,clock,serde,windows-sys --color=always -- --color=always - run: cargo test --lib --features unstable-locales,wasmbind,clock,serde,windows-sys --color=always -- --color=always

View File

@ -11,6 +11,7 @@ readme = "README.md"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
exclude = ["/ci/*"] exclude = ["/ci/*"]
edition = "2018" edition = "2018"
rust-version = "1.56.0"
[lib] [lib]
name = "chrono" name = "chrono"
@ -38,7 +39,7 @@ wasm-bindgen = { version = "0.2", optional = true }
js-sys = { version = "0.3", optional = true } # contains FFI bindings for the JS Date API js-sys = { version = "0.3", optional = true } # contains FFI bindings for the JS Date API
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.48.0", features = ["Win32_System_Time", "Win32_Foundation"], optional = true } windows-sys = { version = "0.48.0", features = ["Win32_System_Time", "Win32_System_SystemInformation", "Win32_Foundation"], optional = true }
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
iana-time-zone = { version = "0.1.45", optional = true, features = ["fallback"] } iana-time-zone = { version = "0.1.45", optional = true, features = ["fallback"] }

View File

@ -64,7 +64,7 @@ fn bench_year_flags_from_year(c: &mut Criterion) {
c.bench_function("bench_year_flags_from_year", |b| { c.bench_function("bench_year_flags_from_year", |b| {
b.iter(|| { b.iter(|| {
for year in -999i32..1000 { for year in -999i32..1000 {
__BenchYearFlags::from_year(year); let _ = __BenchYearFlags::from_year(black_box(year));
} }
}) })
}); });

View File

@ -1 +0,0 @@
msrv = "1.48"

View File

@ -77,6 +77,7 @@ impl<Tz: TimeZone> Date<Tz> {
// //
// note: this constructor is purposely not named to `new` to discourage the direct usage. // note: this constructor is purposely not named to `new` to discourage the direct usage.
#[inline] #[inline]
#[must_use]
pub fn from_utc(date: NaiveDate, offset: Tz::Offset) -> Date<Tz> { pub fn from_utc(date: NaiveDate, offset: Tz::Offset) -> Date<Tz> {
Date { date, offset } Date { date, offset }
} }
@ -86,6 +87,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// ///
/// Panics on invalid datetime. /// Panics on invalid datetime.
#[inline] #[inline]
#[must_use]
pub fn and_time(&self, time: NaiveTime) -> Option<DateTime<Tz>> { pub fn and_time(&self, time: NaiveTime) -> Option<DateTime<Tz>> {
let localdt = self.naive_local().and_time(time); let localdt = self.naive_local().and_time(time);
self.timezone().from_local_datetime(&localdt).single() self.timezone().from_local_datetime(&localdt).single()
@ -97,6 +99,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// Panics on invalid hour, minute and/or second. /// Panics on invalid hour, minute and/or second.
#[deprecated(since = "0.4.23", note = "Use and_hms_opt() instead")] #[deprecated(since = "0.4.23", note = "Use and_hms_opt() instead")]
#[inline] #[inline]
#[must_use]
pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> DateTime<Tz> { pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> DateTime<Tz> {
self.and_hms_opt(hour, min, sec).expect("invalid time") self.and_hms_opt(hour, min, sec).expect("invalid time")
} }
@ -106,6 +109,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// ///
/// Returns `None` on invalid hour, minute and/or second. /// Returns `None` on invalid hour, minute and/or second.
#[inline] #[inline]
#[must_use]
pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<DateTime<Tz>> { pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<DateTime<Tz>> {
NaiveTime::from_hms_opt(hour, min, sec).and_then(|time| self.and_time(time)) NaiveTime::from_hms_opt(hour, min, sec).and_then(|time| self.and_time(time))
} }
@ -117,6 +121,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// Panics on invalid hour, minute, second and/or millisecond. /// Panics on invalid hour, minute, second and/or millisecond.
#[deprecated(since = "0.4.23", note = "Use and_hms_milli_opt() instead")] #[deprecated(since = "0.4.23", note = "Use and_hms_milli_opt() instead")]
#[inline] #[inline]
#[must_use]
pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> DateTime<Tz> { pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> DateTime<Tz> {
self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time") self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time")
} }
@ -127,6 +132,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// ///
/// Returns `None` on invalid hour, minute, second and/or millisecond. /// Returns `None` on invalid hour, minute, second and/or millisecond.
#[inline] #[inline]
#[must_use]
pub fn and_hms_milli_opt( pub fn and_hms_milli_opt(
&self, &self,
hour: u32, hour: u32,
@ -144,6 +150,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// Panics on invalid hour, minute, second and/or microsecond. /// Panics on invalid hour, minute, second and/or microsecond.
#[deprecated(since = "0.4.23", note = "Use and_hms_micro_opt() instead")] #[deprecated(since = "0.4.23", note = "Use and_hms_micro_opt() instead")]
#[inline] #[inline]
#[must_use]
pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> DateTime<Tz> { pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> DateTime<Tz> {
self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time") self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time")
} }
@ -154,6 +161,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// ///
/// Returns `None` on invalid hour, minute, second and/or microsecond. /// Returns `None` on invalid hour, minute, second and/or microsecond.
#[inline] #[inline]
#[must_use]
pub fn and_hms_micro_opt( pub fn and_hms_micro_opt(
&self, &self,
hour: u32, hour: u32,
@ -171,6 +179,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// Panics on invalid hour, minute, second and/or nanosecond. /// Panics on invalid hour, minute, second and/or nanosecond.
#[deprecated(since = "0.4.23", note = "Use and_hms_nano_opt() instead")] #[deprecated(since = "0.4.23", note = "Use and_hms_nano_opt() instead")]
#[inline] #[inline]
#[must_use]
pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> DateTime<Tz> { pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> DateTime<Tz> {
self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time") self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time")
} }
@ -181,6 +190,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// ///
/// Returns `None` on invalid hour, minute, second and/or nanosecond. /// Returns `None` on invalid hour, minute, second and/or nanosecond.
#[inline] #[inline]
#[must_use]
pub fn and_hms_nano_opt( pub fn and_hms_nano_opt(
&self, &self,
hour: u32, hour: u32,
@ -196,6 +206,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// Panics when `self` is the last representable date. /// Panics when `self` is the last representable date.
#[deprecated(since = "0.4.23", note = "Use succ_opt() instead")] #[deprecated(since = "0.4.23", note = "Use succ_opt() instead")]
#[inline] #[inline]
#[must_use]
pub fn succ(&self) -> Date<Tz> { pub fn succ(&self) -> Date<Tz> {
self.succ_opt().expect("out of bound") self.succ_opt().expect("out of bound")
} }
@ -204,6 +215,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// ///
/// Returns `None` when `self` is the last representable date. /// Returns `None` when `self` is the last representable date.
#[inline] #[inline]
#[must_use]
pub fn succ_opt(&self) -> Option<Date<Tz>> { pub fn succ_opt(&self) -> Option<Date<Tz>> {
self.date.succ_opt().map(|date| Date::from_utc(date, self.offset.clone())) self.date.succ_opt().map(|date| Date::from_utc(date, self.offset.clone()))
} }
@ -213,6 +225,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// Panics when `self` is the first representable date. /// Panics when `self` is the first representable date.
#[deprecated(since = "0.4.23", note = "Use pred_opt() instead")] #[deprecated(since = "0.4.23", note = "Use pred_opt() instead")]
#[inline] #[inline]
#[must_use]
pub fn pred(&self) -> Date<Tz> { pub fn pred(&self) -> Date<Tz> {
self.pred_opt().expect("out of bound") self.pred_opt().expect("out of bound")
} }
@ -221,18 +234,21 @@ impl<Tz: TimeZone> Date<Tz> {
/// ///
/// Returns `None` when `self` is the first representable date. /// Returns `None` when `self` is the first representable date.
#[inline] #[inline]
#[must_use]
pub fn pred_opt(&self) -> Option<Date<Tz>> { pub fn pred_opt(&self) -> Option<Date<Tz>> {
self.date.pred_opt().map(|date| Date::from_utc(date, self.offset.clone())) self.date.pred_opt().map(|date| Date::from_utc(date, self.offset.clone()))
} }
/// Retrieves an associated offset from UTC. /// Retrieves an associated offset from UTC.
#[inline] #[inline]
#[must_use]
pub fn offset(&self) -> &Tz::Offset { pub fn offset(&self) -> &Tz::Offset {
&self.offset &self.offset
} }
/// Retrieves an associated time zone. /// Retrieves an associated time zone.
#[inline] #[inline]
#[must_use]
pub fn timezone(&self) -> Tz { pub fn timezone(&self) -> Tz {
TimeZone::from_offset(&self.offset) TimeZone::from_offset(&self.offset)
} }
@ -240,6 +256,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// Changes the associated time zone. /// Changes the associated time zone.
/// This does not change the actual `Date` (but will change the string representation). /// This does not change the actual `Date` (but will change the string representation).
#[inline] #[inline]
#[must_use]
pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> Date<Tz2> { pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> Date<Tz2> {
tz.from_utc_date(&self.date) tz.from_utc_date(&self.date)
} }
@ -248,6 +265,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// ///
/// Returns `None` when it will result in overflow. /// Returns `None` when it will result in overflow.
#[inline] #[inline]
#[must_use]
pub fn checked_add_signed(self, rhs: TimeDelta) -> Option<Date<Tz>> { pub fn checked_add_signed(self, rhs: TimeDelta) -> Option<Date<Tz>> {
let date = self.date.checked_add_signed(rhs)?; let date = self.date.checked_add_signed(rhs)?;
Some(Date { date, offset: self.offset }) Some(Date { date, offset: self.offset })
@ -257,6 +275,7 @@ impl<Tz: TimeZone> Date<Tz> {
/// ///
/// Returns `None` when it will result in overflow. /// Returns `None` when it will result in overflow.
#[inline] #[inline]
#[must_use]
pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option<Date<Tz>> { pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option<Date<Tz>> {
let date = self.date.checked_sub_signed(rhs)?; let date = self.date.checked_sub_signed(rhs)?;
Some(Date { date, offset: self.offset }) Some(Date { date, offset: self.offset })
@ -268,12 +287,14 @@ impl<Tz: TimeZone> Date<Tz> {
/// This does not overflow or underflow at all, /// This does not overflow or underflow at all,
/// as all possible output fits in the range of `Duration`. /// as all possible output fits in the range of `Duration`.
#[inline] #[inline]
#[must_use]
pub fn signed_duration_since<Tz2: TimeZone>(self, rhs: Date<Tz2>) -> TimeDelta { pub fn signed_duration_since<Tz2: TimeZone>(self, rhs: Date<Tz2>) -> TimeDelta {
self.date.signed_duration_since(rhs.date) self.date.signed_duration_since(rhs.date)
} }
/// Returns a view to the naive UTC date. /// Returns a view to the naive UTC date.
#[inline] #[inline]
#[must_use]
pub fn naive_utc(&self) -> NaiveDate { pub fn naive_utc(&self) -> NaiveDate {
self.date self.date
} }
@ -284,11 +305,13 @@ impl<Tz: TimeZone> Date<Tz> {
/// because the offset is restricted to never exceed one day, /// because the offset is restricted to never exceed one day,
/// but provided for the consistency. /// but provided for the consistency.
#[inline] #[inline]
#[must_use]
pub fn naive_local(&self) -> NaiveDate { pub fn naive_local(&self) -> NaiveDate {
self.date self.date
} }
/// Returns the number of whole years from the given `base` until `self`. /// Returns the number of whole years from the given `base` until `self`.
#[must_use]
pub fn years_since(&self, base: Self) -> Option<u32> { pub fn years_since(&self, base: Self) -> Option<u32> {
self.date.years_since(base.date) self.date.years_since(base.date)
} }
@ -315,6 +338,7 @@ where
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline] #[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where where
I: Iterator<Item = B> + Clone, I: Iterator<Item = B> + Clone,
@ -329,6 +353,7 @@ where
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline] #[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt)) self.format_with_items(StrftimeItems::new(fmt))
} }
@ -337,6 +362,7 @@ where
#[cfg(feature = "unstable-locales")] #[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[inline] #[inline]
#[must_use]
pub fn format_localized_with_items<'a, I, B>( pub fn format_localized_with_items<'a, I, B>(
&self, &self,
items: I, items: I,
@ -361,6 +387,7 @@ where
#[cfg(feature = "unstable-locales")] #[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[inline] #[inline]
#[must_use]
pub fn format_localized<'a>( pub fn format_localized<'a>(
&self, &self,
fmt: &'a str, fmt: &'a str,

View File

@ -105,6 +105,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
// //
// note: this constructor is purposely not named to `new` to discourage the direct usage. // note: this constructor is purposely not named to `new` to discourage the direct usage.
#[inline] #[inline]
#[must_use]
pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> { pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> {
DateTime { datetime, offset } DateTime { datetime, offset }
} }
@ -134,6 +135,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west)); /// assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> { pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> {
let datetime_utc = datetime - offset.fix(); let datetime_utc = datetime - offset.fix();
@ -148,6 +150,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
#[inline] #[inline]
#[deprecated(since = "0.4.23", note = "Use `date_naive()` instead")] #[deprecated(since = "0.4.23", note = "Use `date_naive()` instead")]
#[allow(deprecated)] #[allow(deprecated)]
#[must_use]
pub fn date(&self) -> Date<Tz> { pub fn date(&self) -> Date<Tz> {
Date::from_utc(self.naive_local().date(), self.offset.clone()) Date::from_utc(self.naive_local().date(), self.offset.clone())
} }
@ -165,6 +168,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// assert_eq!(date.date_naive(), other.date_naive()); /// assert_eq!(date.date_naive(), other.date_naive());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn date_naive(&self) -> NaiveDate { pub fn date_naive(&self) -> NaiveDate {
let local = self.naive_local(); let local = self.naive_local();
NaiveDate::from_ymd_opt(local.year(), local.month(), local.day()).unwrap() NaiveDate::from_ymd_opt(local.year(), local.month(), local.day()).unwrap()
@ -173,6 +177,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// Retrieves a time component. /// Retrieves a time component.
/// Unlike `date`, this is not associated to the time zone. /// Unlike `date`, this is not associated to the time zone.
#[inline] #[inline]
#[must_use]
pub fn time(&self) -> NaiveTime { pub fn time(&self) -> NaiveTime {
self.datetime.time() + self.offset.fix() self.datetime.time() + self.offset.fix()
} }
@ -180,6 +185,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC /// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC
/// (aka "UNIX timestamp"). /// (aka "UNIX timestamp").
#[inline] #[inline]
#[must_use]
pub fn timestamp(&self) -> i64 { pub fn timestamp(&self) -> i64 {
self.datetime.timestamp() self.datetime.timestamp()
} }
@ -203,6 +209,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn timestamp_millis(&self) -> i64 { pub fn timestamp_millis(&self) -> i64 {
self.datetime.timestamp_millis() self.datetime.timestamp_millis()
} }
@ -226,6 +233,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555); /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn timestamp_micros(&self) -> i64 { pub fn timestamp_micros(&self) -> i64 {
self.datetime.timestamp_micros() self.datetime.timestamp_micros()
} }
@ -249,6 +257,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555); /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn timestamp_nanos(&self) -> i64 { pub fn timestamp_nanos(&self) -> i64 {
self.datetime.timestamp_nanos() self.datetime.timestamp_nanos()
} }
@ -259,6 +268,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// ///
/// note: this is not the number of milliseconds since January 1, 1970 0:00:00 UTC /// note: this is not the number of milliseconds since January 1, 1970 0:00:00 UTC
#[inline] #[inline]
#[must_use]
pub fn timestamp_subsec_millis(&self) -> u32 { pub fn timestamp_subsec_millis(&self) -> u32 {
self.datetime.timestamp_subsec_millis() self.datetime.timestamp_subsec_millis()
} }
@ -269,6 +279,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// ///
/// note: this is not the number of microseconds since January 1, 1970 0:00:00 UTC /// note: this is not the number of microseconds since January 1, 1970 0:00:00 UTC
#[inline] #[inline]
#[must_use]
pub fn timestamp_subsec_micros(&self) -> u32 { pub fn timestamp_subsec_micros(&self) -> u32 {
self.datetime.timestamp_subsec_micros() self.datetime.timestamp_subsec_micros()
} }
@ -279,18 +290,21 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// ///
/// note: this is not the number of nanoseconds since January 1, 1970 0:00:00 UTC /// note: this is not the number of nanoseconds since January 1, 1970 0:00:00 UTC
#[inline] #[inline]
#[must_use]
pub fn timestamp_subsec_nanos(&self) -> u32 { pub fn timestamp_subsec_nanos(&self) -> u32 {
self.datetime.timestamp_subsec_nanos() self.datetime.timestamp_subsec_nanos()
} }
/// Retrieves an associated offset from UTC. /// Retrieves an associated offset from UTC.
#[inline] #[inline]
#[must_use]
pub fn offset(&self) -> &Tz::Offset { pub fn offset(&self) -> &Tz::Offset {
&self.offset &self.offset
} }
/// Retrieves an associated time zone. /// Retrieves an associated time zone.
#[inline] #[inline]
#[must_use]
pub fn timezone(&self) -> Tz { pub fn timezone(&self) -> Tz {
TimeZone::from_offset(&self.offset) TimeZone::from_offset(&self.offset)
} }
@ -298,6 +312,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// Changes the associated time zone. /// Changes the associated time zone.
/// The returned `DateTime` references the same instant of time from the perspective of the provided time zone. /// The returned `DateTime` references the same instant of time from the perspective of the provided time zone.
#[inline] #[inline]
#[must_use]
pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> DateTime<Tz2> { pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> DateTime<Tz2> {
tz.from_utc_datetime(&self.datetime) tz.from_utc_datetime(&self.datetime)
} }
@ -306,6 +321,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// ///
/// Returns `None` when it will result in overflow. /// Returns `None` when it will result in overflow.
#[inline] #[inline]
#[must_use]
pub fn checked_add_signed(self, rhs: TimeDelta) -> Option<DateTime<Tz>> { pub fn checked_add_signed(self, rhs: TimeDelta) -> Option<DateTime<Tz>> {
let datetime = self.datetime.checked_add_signed(rhs)?; let datetime = self.datetime.checked_add_signed(rhs)?;
let tz = self.timezone(); let tz = self.timezone();
@ -318,6 +334,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// local time is not valid on the newly calculated date. /// local time is not valid on the newly calculated date.
/// ///
/// See [`NaiveDate::checked_add_months`] for more details on behavior /// See [`NaiveDate::checked_add_months`] for more details on behavior
#[must_use]
pub fn checked_add_months(self, rhs: Months) -> Option<DateTime<Tz>> { pub fn checked_add_months(self, rhs: Months) -> Option<DateTime<Tz>> {
self.naive_local() self.naive_local()
.checked_add_months(rhs)? .checked_add_months(rhs)?
@ -329,6 +346,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// ///
/// Returns `None` when it will result in overflow. /// Returns `None` when it will result in overflow.
#[inline] #[inline]
#[must_use]
pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option<DateTime<Tz>> { pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option<DateTime<Tz>> {
let datetime = self.datetime.checked_sub_signed(rhs)?; let datetime = self.datetime.checked_sub_signed(rhs)?;
let tz = self.timezone(); let tz = self.timezone();
@ -341,6 +359,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// local time is not valid on the newly calculated date. /// local time is not valid on the newly calculated date.
/// ///
/// See [`NaiveDate::checked_sub_months`] for more details on behavior /// See [`NaiveDate::checked_sub_months`] for more details on behavior
#[must_use]
pub fn checked_sub_months(self, rhs: Months) -> Option<DateTime<Tz>> { pub fn checked_sub_months(self, rhs: Months) -> Option<DateTime<Tz>> {
self.naive_local() self.naive_local()
.checked_sub_months(rhs)? .checked_sub_months(rhs)?
@ -351,6 +370,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// Add a duration in [`Days`] to the date part of the `DateTime` /// Add a duration in [`Days`] to the date part of the `DateTime`
/// ///
/// Returns `None` if the resulting date would be out of range. /// Returns `None` if the resulting date would be out of range.
#[must_use]
pub fn checked_add_days(self, days: Days) -> Option<Self> { pub fn checked_add_days(self, days: Days) -> Option<Self> {
self.naive_local() self.naive_local()
.checked_add_days(days)? .checked_add_days(days)?
@ -361,6 +381,7 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// Subtract a duration in [`Days`] from the date part of the `DateTime` /// Subtract a duration in [`Days`] from the date part of the `DateTime`
/// ///
/// Returns `None` if the resulting date would be out of range. /// Returns `None` if the resulting date would be out of range.
#[must_use]
pub fn checked_sub_days(self, days: Days) -> Option<Self> { pub fn checked_sub_days(self, days: Days) -> Option<Self> {
self.naive_local() self.naive_local()
.checked_sub_days(days)? .checked_sub_days(days)?
@ -371,23 +392,27 @@ impl<Tz: TimeZone> DateTime<Tz> {
/// Subtracts another `DateTime` from the current date and time. /// Subtracts another `DateTime` from the current date and time.
/// This does not overflow or underflow at all. /// This does not overflow or underflow at all.
#[inline] #[inline]
#[must_use]
pub fn signed_duration_since<Tz2: TimeZone>(self, rhs: DateTime<Tz2>) -> TimeDelta { pub fn signed_duration_since<Tz2: TimeZone>(self, rhs: DateTime<Tz2>) -> TimeDelta {
self.datetime.signed_duration_since(rhs.datetime) self.datetime.signed_duration_since(rhs.datetime)
} }
/// Returns a view to the naive UTC datetime. /// Returns a view to the naive UTC datetime.
#[inline] #[inline]
#[must_use]
pub fn naive_utc(&self) -> NaiveDateTime { pub fn naive_utc(&self) -> NaiveDateTime {
self.datetime self.datetime
} }
/// Returns a view to the naive local datetime. /// Returns a view to the naive local datetime.
#[inline] #[inline]
#[must_use]
pub fn naive_local(&self) -> NaiveDateTime { pub fn naive_local(&self) -> NaiveDateTime {
self.datetime + self.offset.fix() self.datetime + self.offset.fix()
} }
/// Retrieve the elapsed years from now to the given [`DateTime`]. /// Retrieve the elapsed years from now to the given [`DateTime`].
#[must_use]
pub fn years_since(&self, base: Self) -> Option<u32> { pub fn years_since(&self, base: Self) -> Option<u32> {
let mut years = self.year() - base.year(); let mut years = self.year() - base.year();
let earlier_time = let earlier_time =
@ -648,6 +673,7 @@ where
/// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`. /// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`.
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[must_use]
pub fn to_rfc2822(&self) -> String { pub fn to_rfc2822(&self) -> String {
let mut result = String::with_capacity(32); let mut result = String::with_capacity(32);
crate::format::write_rfc2822(&mut result, self.naive_local(), self.offset.fix()) crate::format::write_rfc2822(&mut result, self.naive_local(), self.offset.fix())
@ -658,6 +684,7 @@ where
/// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`. /// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[must_use]
pub fn to_rfc3339(&self) -> String { pub fn to_rfc3339(&self) -> String {
let mut result = String::with_capacity(32); let mut result = String::with_capacity(32);
crate::format::write_rfc3339(&mut result, self.naive_local(), self.offset.fix()) crate::format::write_rfc3339(&mut result, self.naive_local(), self.offset.fix())
@ -691,6 +718,7 @@ where
/// ``` /// ```
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[must_use]
pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String { pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String {
use crate::format::Numeric::*; use crate::format::Numeric::*;
use crate::format::Pad::Zero; use crate::format::Pad::Zero;
@ -734,6 +762,7 @@ where
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline] #[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where where
I: Iterator<Item = B> + Clone, I: Iterator<Item = B> + Clone,
@ -758,6 +787,7 @@ where
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline] #[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt)) self.format_with_items(StrftimeItems::new(fmt))
} }
@ -766,6 +796,7 @@ where
#[cfg(feature = "unstable-locales")] #[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[inline] #[inline]
#[must_use]
pub fn format_localized_with_items<'a, I, B>( pub fn format_localized_with_items<'a, I, B>(
&self, &self,
items: I, items: I,
@ -793,6 +824,7 @@ where
#[cfg(feature = "unstable-locales")] #[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[inline] #[inline]
#[must_use]
pub fn format_localized<'a>( pub fn format_localized<'a>(
&self, &self,
fmt: &'a str, fmt: &'a str,

View File

@ -158,6 +158,7 @@ pub mod ts_nanoseconds {
/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -184,6 +185,7 @@ pub mod ts_nanoseconds {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -282,6 +284,7 @@ pub mod ts_nanoseconds_option {
/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -311,6 +314,7 @@ pub mod ts_nanoseconds_option {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -411,6 +415,7 @@ pub mod ts_microseconds {
/// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -437,6 +442,7 @@ pub mod ts_microseconds {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -534,6 +540,7 @@ pub mod ts_microseconds_option {
/// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -563,6 +570,7 @@ pub mod ts_microseconds_option {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -663,6 +671,7 @@ pub mod ts_milliseconds {
/// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -689,6 +698,7 @@ pub mod ts_milliseconds {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -783,6 +793,7 @@ pub mod ts_milliseconds_option {
/// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -824,6 +835,7 @@ pub mod ts_milliseconds_option {
/// assert_eq!(t, E::V(S { time: None })); /// assert_eq!(t, E::V(S { time: None }));
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -925,6 +937,7 @@ pub mod ts_seconds {
/// assert_eq!(as_string, r#"{"time":1431684000}"#); /// assert_eq!(as_string, r#"{"time":1431684000}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -951,6 +964,7 @@ pub mod ts_seconds {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -1042,6 +1056,7 @@ pub mod ts_seconds_option {
/// assert_eq!(as_string, r#"{"time":1431684000}"#); /// assert_eq!(as_string, r#"{"time":1431684000}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -1071,6 +1086,7 @@ pub mod ts_seconds_option {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,

View File

@ -1873,3 +1873,38 @@ fn test_datetime_sub_assign_local() {
assert_eq!(datetime_sub, datetime - TimeDelta::days(i)) assert_eq!(datetime_sub, datetime - TimeDelta::days(i))
} }
} }
#[test]
#[cfg(target_os = "windows")]
fn test_from_naive_date_time_windows() {
let min_year = NaiveDate::from_ymd_opt(1601, 1, 3).unwrap().and_hms_opt(0, 0, 0).unwrap();
let max_year = NaiveDate::from_ymd_opt(30827, 12, 29).unwrap().and_hms_opt(23, 59, 59).unwrap();
let too_low_year =
NaiveDate::from_ymd_opt(1600, 12, 29).unwrap().and_hms_opt(23, 59, 59).unwrap();
let too_high_year = NaiveDate::from_ymd_opt(30829, 1, 3).unwrap().and_hms_opt(0, 0, 0).unwrap();
let _ = Local.from_utc_datetime(&min_year);
let _ = Local.from_utc_datetime(&max_year);
let _ = Local.from_local_datetime(&min_year);
let _ = Local.from_local_datetime(&max_year);
let local_too_low = Local.from_local_datetime(&too_low_year);
let local_too_high = Local.from_local_datetime(&too_high_year);
assert_eq!(local_too_low, LocalResult::None);
assert_eq!(local_too_high, LocalResult::None);
let err = std::panic::catch_unwind(|| {
Local.from_utc_datetime(&too_low_year);
});
assert!(err.is_err());
let err = std::panic::catch_unwind(|| {
Local.from_utc_datetime(&too_high_year);
});
assert!(err.is_err());
}

View File

@ -863,6 +863,7 @@ pub struct DelayedFormat<I> {
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> { impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
/// Makes a new `DelayedFormat` value out of local date and time. /// Makes a new `DelayedFormat` value out of local date and time.
#[must_use]
pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> { pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> {
DelayedFormat { DelayedFormat {
date, date,
@ -875,6 +876,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
} }
/// Makes a new `DelayedFormat` value out of local date and time and UTC offset. /// Makes a new `DelayedFormat` value out of local date and time and UTC offset.
#[must_use]
pub fn new_with_offset<Off>( pub fn new_with_offset<Off>(
date: Option<NaiveDate>, date: Option<NaiveDate>,
time: Option<NaiveTime>, time: Option<NaiveTime>,
@ -898,6 +900,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
/// Makes a new `DelayedFormat` value out of local date and time and locale. /// Makes a new `DelayedFormat` value out of local date and time and locale.
#[cfg(feature = "unstable-locales")] #[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[must_use]
pub fn new_with_locale( pub fn new_with_locale(
date: Option<NaiveDate>, date: Option<NaiveDate>,
time: Option<NaiveTime>, time: Option<NaiveTime>,
@ -910,6 +913,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
/// Makes a new `DelayedFormat` value out of local date and time, UTC offset and locale. /// Makes a new `DelayedFormat` value out of local date and time, UTC offset and locale.
#[cfg(feature = "unstable-locales")] #[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[must_use]
pub fn new_with_offset_and_locale<Off>( pub fn new_with_offset_and_locale<Off>(
date: Option<NaiveDate>, date: Option<NaiveDate>,
time: Option<NaiveTime>, time: Option<NaiveTime>,

View File

@ -1377,6 +1377,28 @@ fn test_rfc2822() {
("Tue, 20 Jan 2015 17:35:20 -0890", Err(OUT_OF_RANGE)), // bad offset ("Tue, 20 Jan 2015 17:35:20 -0890", Err(OUT_OF_RANGE)), // bad offset
("6 Jun 1944 04:00:00Z", Err(INVALID)), // bad offset (zulu not allowed) ("6 Jun 1944 04:00:00Z", Err(INVALID)), // bad offset (zulu not allowed)
("Tue, 20 Jan 2015 17:35:20 HAS", Err(NOT_ENOUGH)), // bad named time zone ("Tue, 20 Jan 2015 17:35:20 HAS", Err(NOT_ENOUGH)), // bad named time zone
// named timezones that have specific timezone offsets
// see https://www.rfc-editor.org/rfc/rfc2822#section-4.3
("Tue, 20 Jan 2015 17:35:20 GMT", Ok("Tue, 20 Jan 2015 17:35:20 +0000")),
("Tue, 20 Jan 2015 17:35:20 UT", Ok("Tue, 20 Jan 2015 17:35:20 +0000")),
("Tue, 20 Jan 2015 17:35:20 ut", Ok("Tue, 20 Jan 2015 17:35:20 +0000")),
("Tue, 20 Jan 2015 17:35:20 EDT", Ok("Tue, 20 Jan 2015 17:35:20 -0400")),
("Tue, 20 Jan 2015 17:35:20 EST", Ok("Tue, 20 Jan 2015 17:35:20 -0500")),
("Tue, 20 Jan 2015 17:35:20 CDT", Ok("Tue, 20 Jan 2015 17:35:20 -0500")),
("Tue, 20 Jan 2015 17:35:20 CST", Ok("Tue, 20 Jan 2015 17:35:20 -0600")),
("Tue, 20 Jan 2015 17:35:20 MDT", Ok("Tue, 20 Jan 2015 17:35:20 -0600")),
("Tue, 20 Jan 2015 17:35:20 MST", Ok("Tue, 20 Jan 2015 17:35:20 -0700")),
("Tue, 20 Jan 2015 17:35:20 PDT", Ok("Tue, 20 Jan 2015 17:35:20 -0700")),
("Tue, 20 Jan 2015 17:35:20 PST", Ok("Tue, 20 Jan 2015 17:35:20 -0800")),
("Tue, 20 Jan 2015 17:35:20 pst", Ok("Tue, 20 Jan 2015 17:35:20 -0800")),
// named single-letter military timezones must fallback to +0000
("Tue, 20 Jan 2015 17:35:20 Z", Ok("Tue, 20 Jan 2015 17:35:20 +0000")),
("Tue, 20 Jan 2015 17:35:20 A", Ok("Tue, 20 Jan 2015 17:35:20 +0000")),
("Tue, 20 Jan 2015 17:35:20 a", Ok("Tue, 20 Jan 2015 17:35:20 +0000")),
("Tue, 20 Jan 2015 17:35:20 K", Ok("Tue, 20 Jan 2015 17:35:20 +0000")),
("Tue, 20 Jan 2015 17:35:20 k", Ok("Tue, 20 Jan 2015 17:35:20 +0000")),
// named single-letter timezone "J" is specifically not valid
("Tue, 20 Jan 2015 17:35:20 J", Err(NOT_ENOUGH)),
("Tue, 20 Jan 2015😈17:35:20 -0800", Err(INVALID)), // bad character! ("Tue, 20 Jan 2015😈17:35:20 -0800", Err(INVALID)), // bad character!
]; ];
@ -1515,3 +1537,11 @@ fn test_rfc3339() {
} }
} }
} }
#[cfg(test)]
#[test]
fn test_issue_1010() {
let dt = crate::NaiveDateTime::parse_from_str("\u{c}SUN\u{e}\u{3000}\0m@J\u{3000}\0\u{3000}\0m\u{c}!\u{c}\u{b}\u{c}\u{c}\u{c}\u{c}%A\u{c}\u{b}\0SU\u{c}\u{c}",
"\u{c}\u{c}%A\u{c}\u{b}\0SUN\u{c}\u{c}\u{c}SUNN\u{c}\u{c}\u{c}SUN\u{c}\u{c}!\u{c}\u{b}\u{c}\u{c}\u{c}\u{c}%A\u{c}\u{b}%a");
assert_eq!(dt, Err(ParseError(ParseErrorKind::Invalid)));
}

View File

@ -122,6 +122,7 @@ fn set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<(
impl Parsed { impl Parsed {
/// Returns the initial value of parsed parts. /// Returns the initial value of parsed parts.
#[must_use]
pub fn new() -> Parsed { pub fn new() -> Parsed {
Parsed::default() Parsed::default()
} }
@ -1287,4 +1288,18 @@ mod tests {
// TODO test with a variable time zone (for None and Ambiguous cases) // TODO test with a variable time zone (for None and Ambiguous cases)
} }
#[test]
fn issue_551() {
use crate::Weekday;
let mut parsed = Parsed::new();
parsed.year = Some(2002);
parsed.week_from_mon = Some(22);
parsed.weekday = Some(Weekday::Mon);
assert_eq!(NaiveDate::from_ymd_opt(2002, 6, 3).unwrap(), parsed.to_naive_date().unwrap());
parsed.year = Some(2001);
assert_eq!(NaiveDate::from_ymd_opt(2001, 5, 28).unwrap(), parsed.to_naive_date().unwrap());
}
} }

View File

@ -12,8 +12,8 @@ use crate::Weekday;
/// Returns true when two slices are equal case-insensitively (in ASCII). /// Returns true when two slices are equal case-insensitively (in ASCII).
/// Assumes that the `pattern` is already converted to lower case. /// Assumes that the `pattern` is already converted to lower case.
fn equals(s: &str, pattern: &str) -> bool { fn equals(s: &[u8], pattern: &str) -> bool {
let mut xs = s.as_bytes().iter().map(|&c| match c { let mut xs = s.iter().map(|&c| match c {
b'A'..=b'Z' => c + 32, b'A'..=b'Z' => c + 32,
_ => c, _ => c,
}); });
@ -152,7 +152,7 @@ pub(super) fn short_or_long_month0(s: &str) -> ParseResult<(&str, u8)> {
// tries to consume the suffix if possible // tries to consume the suffix if possible
let suffix = LONG_MONTH_SUFFIXES[month0 as usize]; let suffix = LONG_MONTH_SUFFIXES[month0 as usize];
if s.len() >= suffix.len() && equals(&s[..suffix.len()], suffix) { if s.len() >= suffix.len() && equals(&s.as_bytes()[..suffix.len()], suffix) {
s = &s[suffix.len()..]; s = &s[suffix.len()..];
} }
@ -170,7 +170,7 @@ pub(super) fn short_or_long_weekday(s: &str) -> ParseResult<(&str, Weekday)> {
// tries to consume the suffix if possible // tries to consume the suffix if possible
let suffix = LONG_WEEKDAY_SUFFIXES[weekday.num_days_from_monday() as usize]; let suffix = LONG_WEEKDAY_SUFFIXES[weekday.num_days_from_monday() as usize];
if s.len() >= suffix.len() && equals(&s[..suffix.len()], suffix) { if s.len() >= suffix.len() && equals(&s.as_bytes()[..suffix.len()], suffix) {
s = &s[suffix.len()..]; s = &s[suffix.len()..];
} }
@ -340,11 +340,15 @@ where
/// Same as `timezone_offset` but also allows for RFC 2822 legacy timezones. /// Same as `timezone_offset` but also allows for RFC 2822 legacy timezones.
/// May return `None` which indicates an insufficient offset data (i.e. `-0000`). /// May return `None` which indicates an insufficient offset data (i.e. `-0000`).
/// See [RFC 2822 Section 4.3].
///
/// [RFC 2822 Section 4.3]: https://tools.ietf.org/html/rfc2822#section-4.3
pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option<i32>)> { pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option<i32>)> {
// tries to parse legacy time zone names // tries to parse legacy time zone names
let upto = s.as_bytes().iter().position(|c| !c.is_ascii_alphabetic()).unwrap_or(s.len()); let upto = s.as_bytes().iter().position(|&c| !c.is_ascii_alphabetic()).unwrap_or(s.len());
if upto > 0 { if upto > 0 {
let (name, s) = s.split_at(upto); let name = &s.as_bytes()[..upto];
let s = &s[upto..];
let offset_hours = |o| Ok((s, Some(o * 3600))); let offset_hours = |o| Ok((s, Some(o * 3600)));
if equals(name, "gmt") || equals(name, "ut") { if equals(name, "gmt") || equals(name, "ut") {
offset_hours(0) offset_hours(0)
@ -358,8 +362,14 @@ pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option<i32>)>
offset_hours(-7) offset_hours(-7)
} else if equals(name, "pst") { } else if equals(name, "pst") {
offset_hours(-8) offset_hours(-8)
} else if name.len() == 1 {
match name[0] {
// recommended by RFC 2822: consume but treat it as -0000
b'a'..=b'i' | b'k'..=b'z' | b'A'..=b'I' | b'K'..=b'Z' => offset_hours(0),
_ => Ok((s, None)),
}
} else { } else {
Ok((s, None)) // recommended by RFC 2822: consume but treat it as -0000 Ok((s, None))
} }
} else { } else {
let (s_, offset) = timezone_offset(s, |s| Ok(s))?; let (s_, offset) = timezone_offset(s, |s| Ok(s))?;

View File

@ -68,7 +68,7 @@ The following specifiers are available both to formatting and parsing.
| `%r` | `12:34:60 AM` | Hour-minute-second format in 12-hour clocks. Same as `%I:%M:%S %p`. | | `%r` | `12:34:60 AM` | Hour-minute-second format in 12-hour clocks. Same as `%I:%M:%S %p`. |
| | | | | | | |
| | | **TIME ZONE SPECIFIERS:** | | | | **TIME ZONE SPECIFIERS:** |
| `%Z` | `ACST` | Local time zone name. Skips all non-whitespace characters during parsing. [^8] | | `%Z` | `ACST` | Local time zone name. Skips all non-whitespace characters during parsing. Identical to `%:z` when formatting. [^8] |
| `%z` | `+0930` | Offset from the local time to UTC (with UTC being `+0000`). | | `%z` | `+0930` | Offset from the local time to UTC (with UTC being `+0000`). |
| `%:z` | `+09:30` | Same as `%z` but with a colon. | | `%:z` | `+09:30` | Same as `%z` but with a colon. |
|`%::z`|`+09:30:00`| Offset from the local time to UTC with seconds. | |`%::z`|`+09:30:00`| Offset from the local time to UTC with seconds. |
@ -164,6 +164,12 @@ Notes:
Note that they can read nothing if the fractional part is zero. Note that they can read nothing if the fractional part is zero.
[^8]: `%Z`: [^8]: `%Z`:
Since `chrono` is not aware of timezones beyond their offsets, this specifier
**only prints the offset** when used for formatting. The timezone abbreviation
will NOT be printed. See [this issue](https://github.com/chronotope/chrono/issues/960)
for more information.
<br>
<br>
Offset will not be populated from the parsed data, nor will it be validated. Offset will not be populated from the parsed data, nor will it be validated.
Timezone is completely ignored. Similar to the glibc `strptime` treatment of Timezone is completely ignored. Similar to the glibc `strptime` treatment of
this format code. this format code.
@ -227,6 +233,7 @@ pub struct StrftimeItems<'a> {
impl<'a> StrftimeItems<'a> { impl<'a> StrftimeItems<'a> {
/// Creates a new parsing iterator from the `strftime`-like format string. /// Creates a new parsing iterator from the `strftime`-like format string.
#[must_use]
pub fn new(s: &'a str) -> StrftimeItems<'a> { pub fn new(s: &'a str) -> StrftimeItems<'a> {
Self::with_remainer(s) Self::with_remainer(s)
} }
@ -234,6 +241,7 @@ impl<'a> StrftimeItems<'a> {
/// Creates a new parsing iterator from the `strftime`-like format string. /// Creates a new parsing iterator from the `strftime`-like format string.
#[cfg(feature = "unstable-locales")] #[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[must_use]
pub fn new_with_locale(s: &'a str, locale: Locale) -> StrftimeItems<'a> { pub fn new_with_locale(s: &'a str, locale: Locale) -> StrftimeItems<'a> {
let d_fmt = StrftimeItems::new(locales::d_fmt(locale)).collect(); let d_fmt = StrftimeItems::new(locales::d_fmt(locale)).collect();
let d_t_fmt = StrftimeItems::new(locales::d_t_fmt(locale)).collect(); let d_t_fmt = StrftimeItems::new(locales::d_t_fmt(locale)).collect();

View File

@ -519,15 +519,3 @@ impl fmt::Debug for OutOfRange {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for OutOfRange {} impl std::error::Error for OutOfRange {}
/// MSRV 1.42
#[cfg(test)]
#[macro_export]
macro_rules! matches {
($expression:expr, $(|)? $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
match $expression {
$( $pattern )|+ $( if $guard )? => true,
_ => false
}
}
}

View File

@ -29,7 +29,7 @@ use crate::OutOfRange;
/// Allows mapping from and to month, from 1-January to 12-December. /// Allows mapping from and to month, from 1-January to 12-December.
/// Can be Serialized/Deserialized with serde /// Can be Serialized/Deserialized with serde
// Actual implementation is zero-indexed, API intended as 1-indexed for more intuitive behavior. // Actual implementation is zero-indexed, API intended as 1-indexed for more intuitive behavior.
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Month { pub enum Month {
@ -66,6 +66,7 @@ impl Month {
/// ----------- | --------- | ---------- | --- | --------- /// ----------- | --------- | ---------- | --- | ---------
/// `m.succ()`: | `February` | `March` | `...` | `January` /// `m.succ()`: | `February` | `March` | `...` | `January`
#[inline] #[inline]
#[must_use]
pub const fn succ(&self) -> Month { pub const fn succ(&self) -> Month {
match *self { match *self {
Month::January => Month::February, Month::January => Month::February,
@ -89,6 +90,7 @@ impl Month {
/// ----------- | --------- | ---------- | --- | --------- /// ----------- | --------- | ---------- | --- | ---------
/// `m.pred()`: | `December` | `January` | `...` | `November` /// `m.pred()`: | `December` | `January` | `...` | `November`
#[inline] #[inline]
#[must_use]
pub const fn pred(&self) -> Month { pub const fn pred(&self) -> Month {
match *self { match *self {
Month::January => Month::December, Month::January => Month::December,
@ -112,6 +114,7 @@ impl Month {
/// -------------------------| --------- | ---------- | --- | ----- /// -------------------------| --------- | ---------- | --- | -----
/// `m.number_from_month()`: | 1 | 2 | `...` | 12 /// `m.number_from_month()`: | 1 | 2 | `...` | 12
#[inline] #[inline]
#[must_use]
pub const fn number_from_month(&self) -> u32 { pub const fn number_from_month(&self) -> u32 {
match *self { match *self {
Month::January => 1, Month::January => 1,
@ -136,6 +139,7 @@ impl Month {
/// ///
/// assert_eq!(Month::January.name(), "January") /// assert_eq!(Month::January.name(), "January")
/// ``` /// ```
#[must_use]
pub const fn name(&self) -> &'static str { pub const fn name(&self) -> &'static str {
match *self { match *self {
Month::January => "January", Month::January => "January",
@ -334,4 +338,13 @@ mod tests {
assert_eq!(Month::January.pred(), Month::December); assert_eq!(Month::January.pred(), Month::December);
assert_eq!(Month::February.pred(), Month::January); assert_eq!(Month::February.pred(), Month::January);
} }
#[test]
fn test_month_partial_ord() {
assert!(Month::January <= Month::January);
assert!(Month::January < Month::February);
assert!(Month::January < Month::December);
assert!(Month::July >= Month::May);
assert!(Month::September > Month::March);
}
} }

View File

@ -75,6 +75,7 @@ impl NaiveWeek {
/// assert!(week.first_day() <= date); /// assert!(week.first_day() <= date);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn first_day(&self) -> NaiveDate { pub fn first_day(&self) -> NaiveDate {
let start = self.start.num_days_from_monday(); let start = self.start.num_days_from_monday();
let end = self.date.weekday().num_days_from_monday(); let end = self.date.weekday().num_days_from_monday();
@ -94,6 +95,7 @@ impl NaiveWeek {
/// assert!(week.last_day() >= date); /// assert!(week.last_day() >= date);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn last_day(&self) -> NaiveDate { pub fn last_day(&self) -> NaiveDate {
self.first_day() + TimeDelta::days(6) self.first_day() + TimeDelta::days(6)
} }
@ -113,6 +115,7 @@ impl NaiveWeek {
/// assert!(days.contains(&date)); /// assert!(days.contains(&date));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn days(&self) -> RangeInclusive<NaiveDate> { pub fn days(&self) -> RangeInclusive<NaiveDate> {
self.first_day()..=self.last_day() self.first_day()..=self.last_day()
} }
@ -257,6 +260,7 @@ impl NaiveDate {
/// ///
/// Panics on the out-of-range date, invalid month and/or day. /// Panics on the out-of-range date, invalid month and/or day.
#[deprecated(since = "0.4.23", note = "use `from_ymd_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_ymd_opt()` instead")]
#[must_use]
pub fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate { pub fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate {
NaiveDate::from_ymd_opt(year, month, day).expect("invalid or out-of-range date") NaiveDate::from_ymd_opt(year, month, day).expect("invalid or out-of-range date")
} }
@ -280,6 +284,7 @@ impl NaiveDate {
/// assert!(from_ymd_opt(400000, 1, 1).is_none()); /// assert!(from_ymd_opt(400000, 1, 1).is_none());
/// assert!(from_ymd_opt(-400000, 1, 1).is_none()); /// assert!(from_ymd_opt(-400000, 1, 1).is_none());
/// ``` /// ```
#[must_use]
pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> { pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option<NaiveDate> {
let flags = YearFlags::from_year(year); let flags = YearFlags::from_year(year);
NaiveDate::from_mdf(year, Mdf::new(month, day, flags)?) NaiveDate::from_mdf(year, Mdf::new(month, day, flags)?)
@ -290,6 +295,7 @@ impl NaiveDate {
/// ///
/// Panics on the out-of-range date and/or invalid day of year. /// Panics on the out-of-range date and/or invalid day of year.
#[deprecated(since = "0.4.23", note = "use `from_yo_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_yo_opt()` instead")]
#[must_use]
pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate { pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate {
NaiveDate::from_yo_opt(year, ordinal).expect("invalid or out-of-range date") NaiveDate::from_yo_opt(year, ordinal).expect("invalid or out-of-range date")
} }
@ -314,6 +320,7 @@ impl NaiveDate {
/// assert!(from_yo_opt(400000, 1).is_none()); /// assert!(from_yo_opt(400000, 1).is_none());
/// assert!(from_yo_opt(-400000, 1).is_none()); /// assert!(from_yo_opt(-400000, 1).is_none());
/// ``` /// ```
#[must_use]
pub fn from_yo_opt(year: i32, ordinal: u32) -> Option<NaiveDate> { pub fn from_yo_opt(year: i32, ordinal: u32) -> Option<NaiveDate> {
let flags = YearFlags::from_year(year); let flags = YearFlags::from_year(year);
NaiveDate::from_of(year, Of::new(ordinal, flags)?) NaiveDate::from_of(year, Of::new(ordinal, flags)?)
@ -325,6 +332,7 @@ impl NaiveDate {
/// ///
/// Panics on the out-of-range date and/or invalid week number. /// Panics on the out-of-range date and/or invalid week number.
#[deprecated(since = "0.4.23", note = "use `from_isoywd_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_isoywd_opt()` instead")]
#[must_use]
pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> NaiveDate { pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> NaiveDate {
NaiveDate::from_isoywd_opt(year, week, weekday).expect("invalid or out-of-range date") NaiveDate::from_isoywd_opt(year, week, weekday).expect("invalid or out-of-range date")
} }
@ -373,6 +381,7 @@ impl NaiveDate {
/// assert_eq!(from_isoywd_opt(2015, 54, Weekday::Mon), None); /// assert_eq!(from_isoywd_opt(2015, 54, Weekday::Mon), None);
/// assert_eq!(from_isoywd_opt(2016, 1, Weekday::Mon), Some(from_ymd(2016, 1, 4))); /// assert_eq!(from_isoywd_opt(2016, 1, Weekday::Mon), Some(from_ymd(2016, 1, 4)));
/// ``` /// ```
#[must_use]
pub fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option<NaiveDate> { pub fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option<NaiveDate> {
let flags = YearFlags::from_year(year); let flags = YearFlags::from_year(year);
let nweeks = flags.nisoweeks(); let nweeks = flags.nisoweeks();
@ -410,6 +419,7 @@ impl NaiveDate {
/// Panics if the date is out of range. /// Panics if the date is out of range.
#[deprecated(since = "0.4.23", note = "use `from_num_days_from_ce_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_num_days_from_ce_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn from_num_days_from_ce(days: i32) -> NaiveDate { pub fn from_num_days_from_ce(days: i32) -> NaiveDate {
NaiveDate::from_num_days_from_ce_opt(days).expect("out-of-range date") NaiveDate::from_num_days_from_ce_opt(days).expect("out-of-range date")
} }
@ -434,8 +444,9 @@ impl NaiveDate {
/// assert_eq!(from_ndays_opt(100_000_000), None); /// assert_eq!(from_ndays_opt(100_000_000), None);
/// assert_eq!(from_ndays_opt(-100_000_000), None); /// assert_eq!(from_ndays_opt(-100_000_000), None);
/// ``` /// ```
#[must_use]
pub fn from_num_days_from_ce_opt(days: i32) -> Option<NaiveDate> { pub fn from_num_days_from_ce_opt(days: i32) -> Option<NaiveDate> {
let days = days + 365; // make December 31, 1 BCE equal to day 0 let days = days.checked_add(365)?; // make December 31, 1 BCE equal to day 0
let (year_div_400, cycle) = div_mod_floor(days, 146_097); let (year_div_400, cycle) = div_mod_floor(days, 146_097);
let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32);
let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); let flags = YearFlags::from_year_mod_400(year_mod_400 as i32);
@ -453,6 +464,7 @@ impl NaiveDate {
/// ///
/// `n` is 1-indexed. Passing `n=0` will cause a panic. /// `n` is 1-indexed. Passing `n=0` will cause a panic.
#[deprecated(since = "0.4.23", note = "use `from_weekday_of_month_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_weekday_of_month_opt()` instead")]
#[must_use]
pub fn from_weekday_of_month(year: i32, month: u32, weekday: Weekday, n: u8) -> NaiveDate { pub fn from_weekday_of_month(year: i32, month: u32, weekday: Weekday, n: u8) -> NaiveDate {
NaiveDate::from_weekday_of_month_opt(year, month, weekday, n).expect("out-of-range date") NaiveDate::from_weekday_of_month_opt(year, month, weekday, n).expect("out-of-range date")
} }
@ -469,6 +481,7 @@ impl NaiveDate {
/// ///
/// Returns `None` if `n` out-of-range; ie. if `n` is larger than the number of `weekday` in /// Returns `None` if `n` out-of-range; ie. if `n` is larger than the number of `weekday` in
/// `month` (eg. the 6th Friday of March 2017), or if `n == 0`. /// `month` (eg. the 6th Friday of March 2017), or if `n == 0`.
#[must_use]
pub fn from_weekday_of_month_opt( pub fn from_weekday_of_month_opt(
year: i32, year: i32,
month: u32, month: u32,
@ -549,6 +562,7 @@ impl NaiveDate {
/// Some(NaiveDate::from_ymd_opt(2022, 9, 30).unwrap()) /// Some(NaiveDate::from_ymd_opt(2022, 9, 30).unwrap())
/// ); /// );
/// ``` /// ```
#[must_use]
pub fn checked_add_months(self, months: Months) -> Option<Self> { pub fn checked_add_months(self, months: Months) -> Option<Self> {
if months.0 == 0 { if months.0 == 0 {
return Some(self); return Some(self);
@ -579,6 +593,7 @@ impl NaiveDate {
/// None /// None
/// ); /// );
/// ``` /// ```
#[must_use]
pub fn checked_sub_months(self, months: Months) -> Option<Self> { pub fn checked_sub_months(self, months: Months) -> Option<Self> {
if months.0 == 0 { if months.0 == 0 {
return Some(self); return Some(self);
@ -652,6 +667,7 @@ impl NaiveDate {
/// None /// None
/// ); /// );
/// ``` /// ```
#[must_use]
pub fn checked_add_days(self, days: Days) -> Option<Self> { pub fn checked_add_days(self, days: Days) -> Option<Self> {
if days.0 == 0 { if days.0 == 0 {
return Some(self); return Some(self);
@ -675,6 +691,7 @@ impl NaiveDate {
/// None /// None
/// ); /// );
/// ``` /// ```
#[must_use]
pub fn checked_sub_days(self, days: Days) -> Option<Self> { pub fn checked_sub_days(self, days: Days) -> Option<Self> {
if days.0 == 0 { if days.0 == 0 {
return Some(self); return Some(self);
@ -706,6 +723,7 @@ impl NaiveDate {
/// assert_eq!(dt.time(), t); /// assert_eq!(dt.time(), t);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub const fn and_time(&self, time: NaiveTime) -> NaiveDateTime { pub const fn and_time(&self, time: NaiveTime) -> NaiveDateTime {
NaiveDateTime::new(*self, time) NaiveDateTime::new(*self, time)
} }
@ -718,6 +736,7 @@ impl NaiveDate {
/// Panics on invalid hour, minute and/or second. /// Panics on invalid hour, minute and/or second.
#[deprecated(since = "0.4.23", note = "use `and_hms_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `and_hms_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime { pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime {
self.and_hms_opt(hour, min, sec).expect("invalid time") self.and_hms_opt(hour, min, sec).expect("invalid time")
} }
@ -741,6 +760,7 @@ impl NaiveDate {
/// assert!(d.and_hms_opt(24, 34, 56).is_none()); /// assert!(d.and_hms_opt(24, 34, 56).is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<NaiveDateTime> { pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<NaiveDateTime> {
NaiveTime::from_hms_opt(hour, min, sec).map(|time| self.and_time(time)) NaiveTime::from_hms_opt(hour, min, sec).map(|time| self.and_time(time))
} }
@ -753,6 +773,7 @@ impl NaiveDate {
/// Panics on invalid hour, minute, second and/or millisecond. /// Panics on invalid hour, minute, second and/or millisecond.
#[deprecated(since = "0.4.23", note = "use `and_hms_milli_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `and_hms_milli_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> NaiveDateTime { pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> NaiveDateTime {
self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time") self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time")
} }
@ -778,6 +799,7 @@ impl NaiveDate {
/// assert!(d.and_hms_milli_opt(24, 34, 56, 789).is_none()); /// assert!(d.and_hms_milli_opt(24, 34, 56, 789).is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn and_hms_milli_opt( pub fn and_hms_milli_opt(
&self, &self,
hour: u32, hour: u32,
@ -810,6 +832,7 @@ impl NaiveDate {
/// ``` /// ```
#[deprecated(since = "0.4.23", note = "use `and_hms_micro_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `and_hms_micro_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> NaiveDateTime { pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> NaiveDateTime {
self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time") self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time")
} }
@ -835,6 +858,7 @@ impl NaiveDate {
/// assert!(d.and_hms_micro_opt(24, 34, 56, 789_012).is_none()); /// assert!(d.and_hms_micro_opt(24, 34, 56, 789_012).is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn and_hms_micro_opt( pub fn and_hms_micro_opt(
&self, &self,
hour: u32, hour: u32,
@ -853,6 +877,7 @@ impl NaiveDate {
/// Panics on invalid hour, minute, second and/or nanosecond. /// Panics on invalid hour, minute, second and/or nanosecond.
#[deprecated(since = "0.4.23", note = "use `and_hms_nano_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `and_hms_nano_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> NaiveDateTime { pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> NaiveDateTime {
self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time") self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time")
} }
@ -878,6 +903,7 @@ impl NaiveDate {
/// assert!(d.and_hms_nano_opt(24, 34, 56, 789_012_345).is_none()); /// assert!(d.and_hms_nano_opt(24, 34, 56, 789_012_345).is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn and_hms_nano_opt( pub fn and_hms_nano_opt(
&self, &self,
hour: u32, hour: u32,
@ -926,6 +952,7 @@ impl NaiveDate {
/// Panics when `self` is the last representable date. /// Panics when `self` is the last representable date.
#[deprecated(since = "0.4.23", note = "use `succ_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `succ_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn succ(&self) -> NaiveDate { pub fn succ(&self) -> NaiveDate {
self.succ_opt().expect("out of bound") self.succ_opt().expect("out of bound")
} }
@ -944,6 +971,7 @@ impl NaiveDate {
/// assert_eq!(NaiveDate::MAX.succ_opt(), None); /// assert_eq!(NaiveDate::MAX.succ_opt(), None);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn succ_opt(&self) -> Option<NaiveDate> { pub fn succ_opt(&self) -> Option<NaiveDate> {
self.with_of(self.of().succ()).or_else(|| NaiveDate::from_ymd_opt(self.year() + 1, 1, 1)) self.with_of(self.of().succ()).or_else(|| NaiveDate::from_ymd_opt(self.year() + 1, 1, 1))
} }
@ -953,6 +981,7 @@ impl NaiveDate {
/// Panics when `self` is the first representable date. /// Panics when `self` is the first representable date.
#[deprecated(since = "0.4.23", note = "use `pred_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `pred_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn pred(&self) -> NaiveDate { pub fn pred(&self) -> NaiveDate {
self.pred_opt().expect("out of bound") self.pred_opt().expect("out of bound")
} }
@ -971,6 +1000,7 @@ impl NaiveDate {
/// assert_eq!(NaiveDate::MIN.pred_opt(), None); /// assert_eq!(NaiveDate::MIN.pred_opt(), None);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn pred_opt(&self) -> Option<NaiveDate> { pub fn pred_opt(&self) -> Option<NaiveDate> {
self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31)) self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31))
} }
@ -993,6 +1023,7 @@ impl NaiveDate {
/// assert_eq!(d.checked_add_signed(TimeDelta::days(-1_000_000_000)), None); /// assert_eq!(d.checked_add_signed(TimeDelta::days(-1_000_000_000)), None);
/// assert_eq!(NaiveDate::MAX.checked_add_signed(TimeDelta::days(1)), None); /// assert_eq!(NaiveDate::MAX.checked_add_signed(TimeDelta::days(1)), None);
/// ``` /// ```
#[must_use]
pub fn checked_add_signed(self, rhs: TimeDelta) -> Option<NaiveDate> { pub fn checked_add_signed(self, rhs: TimeDelta) -> Option<NaiveDate> {
let year = self.year(); let year = self.year();
let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400);
@ -1024,6 +1055,7 @@ impl NaiveDate {
/// assert_eq!(d.checked_sub_signed(TimeDelta::days(-1_000_000_000)), None); /// assert_eq!(d.checked_sub_signed(TimeDelta::days(-1_000_000_000)), None);
/// assert_eq!(NaiveDate::MIN.checked_sub_signed(TimeDelta::days(1)), None); /// assert_eq!(NaiveDate::MIN.checked_sub_signed(TimeDelta::days(1)), None);
/// ``` /// ```
#[must_use]
pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option<NaiveDate> { pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option<NaiveDate> {
let year = self.year(); let year = self.year();
let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400);
@ -1059,6 +1091,7 @@ impl NaiveDate {
/// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)), TimeDelta::days(365*4 + 1)); /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)), TimeDelta::days(365*4 + 1));
/// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)), TimeDelta::days(365*400 + 97)); /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)), TimeDelta::days(365*400 + 97));
/// ``` /// ```
#[must_use]
pub fn signed_duration_since(self, rhs: NaiveDate) -> TimeDelta { pub fn signed_duration_since(self, rhs: NaiveDate) -> TimeDelta {
let year1 = self.year(); let year1 = self.year();
let year2 = rhs.year(); let year2 = rhs.year();
@ -1072,6 +1105,7 @@ impl NaiveDate {
} }
/// Returns the number of whole years from the given `base` until `self`. /// Returns the number of whole years from the given `base` until `self`.
#[must_use]
pub fn years_since(&self, base: Self) -> Option<u32> { pub fn years_since(&self, base: Self) -> Option<u32> {
let mut years = self.year() - base.year(); let mut years = self.year() - base.year();
if (self.month(), self.day()) < (base.month(), base.day()) { if (self.month(), self.day()) < (base.month(), base.day()) {
@ -1114,6 +1148,7 @@ impl NaiveDate {
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline] #[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where where
I: Iterator<Item = B> + Clone, I: Iterator<Item = B> + Clone,
@ -1157,6 +1192,7 @@ impl NaiveDate {
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline] #[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt)) self.format_with_items(StrftimeItems::new(fmt))
} }
@ -1165,6 +1201,7 @@ impl NaiveDate {
#[cfg(feature = "unstable-locales")] #[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[inline] #[inline]
#[must_use]
pub fn format_localized_with_items<'a, I, B>( pub fn format_localized_with_items<'a, I, B>(
&self, &self,
items: I, items: I,
@ -1184,6 +1221,7 @@ impl NaiveDate {
#[cfg(feature = "unstable-locales")] #[cfg(feature = "unstable-locales")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
#[inline] #[inline]
#[must_use]
pub fn format_localized<'a>( pub fn format_localized<'a>(
&self, &self,
fmt: &'a str, fmt: &'a str,
@ -1519,7 +1557,8 @@ impl Datelike for NaiveDate {
/// ``` /// ```
#[inline] #[inline]
fn with_month0(&self, month0: u32) -> Option<NaiveDate> { fn with_month0(&self, month0: u32) -> Option<NaiveDate> {
self.with_mdf(self.mdf().with_month(month0 + 1)?) let month = month0.checked_add(1)?;
self.with_mdf(self.mdf().with_month(month)?)
} }
/// Makes a new `NaiveDate` with the day of month (starting from 1) changed. /// Makes a new `NaiveDate` with the day of month (starting from 1) changed.
@ -1557,7 +1596,8 @@ impl Datelike for NaiveDate {
/// ``` /// ```
#[inline] #[inline]
fn with_day0(&self, day0: u32) -> Option<NaiveDate> { fn with_day0(&self, day0: u32) -> Option<NaiveDate> {
self.with_mdf(self.mdf().with_day(day0 + 1)?) let day = day0.checked_add(1)?;
self.with_mdf(self.mdf().with_day(day)?)
} }
/// Makes a new `NaiveDate` with the day of year (starting from 1) changed. /// Makes a new `NaiveDate` with the day of year (starting from 1) changed.
@ -1605,7 +1645,8 @@ impl Datelike for NaiveDate {
/// ``` /// ```
#[inline] #[inline]
fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDate> { fn with_ordinal0(&self, ordinal0: u32) -> Option<NaiveDate> {
self.with_of(self.of().with_ordinal(ordinal0 + 1)?) let ordinal = ordinal0.checked_add(1)?;
self.with_of(self.of().with_ordinal(ordinal)?)
} }
} }
@ -1788,6 +1829,12 @@ impl Sub<NaiveDate> for NaiveDate {
} }
} }
impl From<NaiveDateTime> for NaiveDate {
fn from(naive_datetime: NaiveDateTime) -> Self {
naive_datetime.date()
}
}
/// Iterator over `NaiveDate` with a step size of one day. /// Iterator over `NaiveDate` with a step size of one day.
#[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)] #[derive(Debug, Copy, Clone, Hash, PartialEq, PartialOrd, Eq, Ord)]
pub struct NaiveDateDaysIterator { pub struct NaiveDateDaysIterator {
@ -2170,7 +2217,7 @@ mod tests {
assert_eq!( assert_eq!(
NaiveDate::from_ymd_opt(2022, 8, 3) NaiveDate::from_ymd_opt(2022, 8, 3)
.unwrap() .unwrap()
.checked_sub_months(Months::new((i32::MIN as i64).abs() as u32 + 1)), .checked_sub_months(Months::new(i32::MIN.unsigned_abs() + 1)),
None None
); );
@ -2421,6 +2468,9 @@ mod tests {
assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce() - 1), None); assert_eq!(from_ndays_from_ce(NaiveDate::MIN.num_days_from_ce() - 1), None);
assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce()), Some(NaiveDate::MAX)); assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce()), Some(NaiveDate::MAX));
assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce() + 1), None); assert_eq!(from_ndays_from_ce(NaiveDate::MAX.num_days_from_ce() + 1), None);
assert_eq!(from_ndays_from_ce(i32::MIN), None);
assert_eq!(from_ndays_from_ce(i32::MAX), None);
} }
#[test] #[test]
@ -2984,4 +3034,12 @@ mod tests {
} }
} }
} }
#[test]
fn test_with_0_overflow() {
let dt = NaiveDate::from_ymd_opt(2023, 4, 18).unwrap();
assert!(dt.with_month0(4294967295).is_none());
assert!(dt.with_day0(4294967295).is_none());
assert!(dt.with_ordinal0(4294967295).is_none());
}
} }

View File

@ -145,6 +145,7 @@ impl NaiveDateTime {
/// Panics on the out-of-range number of seconds and/or invalid nanosecond. /// Panics on the out-of-range number of seconds and/or invalid nanosecond.
#[deprecated(since = "0.4.23", note = "use `from_timestamp_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_timestamp_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn from_timestamp(secs: i64, nsecs: u32) -> NaiveDateTime { pub fn from_timestamp(secs: i64, nsecs: u32) -> NaiveDateTime {
let datetime = NaiveDateTime::from_timestamp_opt(secs, nsecs); let datetime = NaiveDateTime::from_timestamp_opt(secs, nsecs);
datetime.expect("invalid or out-of-range datetime") datetime.expect("invalid or out-of-range datetime")
@ -172,6 +173,7 @@ impl NaiveDateTime {
/// assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis()); /// assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> { pub fn from_timestamp_millis(millis: i64) -> Option<NaiveDateTime> {
Self::from_timestamp_unit(millis, TimestampUnit::Millis) Self::from_timestamp_unit(millis, TimestampUnit::Millis)
} }
@ -198,6 +200,7 @@ impl NaiveDateTime {
/// assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros()); /// assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn from_timestamp_micros(micros: i64) -> Option<NaiveDateTime> { pub fn from_timestamp_micros(micros: i64) -> Option<NaiveDateTime> {
Self::from_timestamp_unit(micros, TimestampUnit::Micros) Self::from_timestamp_unit(micros, TimestampUnit::Micros)
} }
@ -229,6 +232,7 @@ impl NaiveDateTime {
/// assert!(from_timestamp_opt(i64::MAX, 0).is_none()); /// assert!(from_timestamp_opt(i64::MAX, 0).is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn from_timestamp_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> { pub fn from_timestamp_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> {
let (days, secs) = div_mod_floor(secs, 86_400); let (days, secs) = div_mod_floor(secs, 86_400);
let date = i32::try_from(days) let date = i32::try_from(days)
@ -372,6 +376,7 @@ impl NaiveDateTime {
/// assert_eq!(dt.timestamp(), -62198755200); /// assert_eq!(dt.timestamp(), -62198755200);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn timestamp(&self) -> i64 { pub fn timestamp(&self) -> i64 {
const UNIX_EPOCH_DAY: i64 = 719_163; const UNIX_EPOCH_DAY: i64 = 719_163;
let gregorian_day = i64::from(self.date.num_days_from_ce()); let gregorian_day = i64::from(self.date.num_days_from_ce());
@ -404,6 +409,7 @@ impl NaiveDateTime {
/// assert_eq!(dt.timestamp_millis(), -900); /// assert_eq!(dt.timestamp_millis(), -900);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn timestamp_millis(&self) -> i64 { pub fn timestamp_millis(&self) -> i64 {
let as_ms = self.timestamp() * 1000; let as_ms = self.timestamp() * 1000;
as_ms + i64::from(self.timestamp_subsec_millis()) as_ms + i64::from(self.timestamp_subsec_millis())
@ -431,6 +437,7 @@ impl NaiveDateTime {
/// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555); /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn timestamp_micros(&self) -> i64 { pub fn timestamp_micros(&self) -> i64 {
let as_us = self.timestamp() * 1_000_000; let as_us = self.timestamp() * 1_000_000;
as_us + i64::from(self.timestamp_subsec_micros()) as_us + i64::from(self.timestamp_subsec_micros())
@ -470,6 +477,7 @@ impl NaiveDateTime {
/// ); /// );
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn timestamp_nanos(&self) -> i64 { pub fn timestamp_nanos(&self) -> i64 {
let as_ns = self.timestamp() * 1_000_000_000; let as_ns = self.timestamp() * 1_000_000_000;
as_ns + i64::from(self.timestamp_subsec_nanos()) as_ns + i64::from(self.timestamp_subsec_nanos())
@ -492,6 +500,7 @@ impl NaiveDateTime {
/// assert_eq!(dt.timestamp_subsec_millis(), 1_234); /// assert_eq!(dt.timestamp_subsec_millis(), 1_234);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn timestamp_subsec_millis(&self) -> u32 { pub fn timestamp_subsec_millis(&self) -> u32 {
self.timestamp_subsec_nanos() / 1_000_000 self.timestamp_subsec_nanos() / 1_000_000
} }
@ -513,6 +522,7 @@ impl NaiveDateTime {
/// assert_eq!(dt.timestamp_subsec_micros(), 1_234_567); /// assert_eq!(dt.timestamp_subsec_micros(), 1_234_567);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn timestamp_subsec_micros(&self) -> u32 { pub fn timestamp_subsec_micros(&self) -> u32 {
self.timestamp_subsec_nanos() / 1_000 self.timestamp_subsec_nanos() / 1_000
} }
@ -534,6 +544,7 @@ impl NaiveDateTime {
/// assert_eq!(dt.timestamp_subsec_nanos(), 1_234_567_890); /// assert_eq!(dt.timestamp_subsec_nanos(), 1_234_567_890);
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn timestamp_subsec_nanos(&self) -> u32 { pub fn timestamp_subsec_nanos(&self) -> u32 {
self.time.nanosecond() self.time.nanosecond()
} }
@ -603,6 +614,7 @@ impl NaiveDateTime {
/// assert_eq!(leap.checked_add_signed(TimeDelta::days(1)), /// assert_eq!(leap.checked_add_signed(TimeDelta::days(1)),
/// Some(from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap())); /// Some(from_ymd(2016, 7, 9).and_hms_milli_opt(3, 5, 59, 300).unwrap()));
/// ``` /// ```
#[must_use]
pub fn checked_add_signed(self, rhs: TimeDelta) -> Option<NaiveDateTime> { pub fn checked_add_signed(self, rhs: TimeDelta) -> Option<NaiveDateTime> {
let (time, rhs) = self.time.overflowing_add_signed(rhs); let (time, rhs) = self.time.overflowing_add_signed(rhs);
@ -639,6 +651,7 @@ impl NaiveDateTime {
/// None /// None
/// ); /// );
/// ``` /// ```
#[must_use]
pub fn checked_add_months(self, rhs: Months) -> Option<NaiveDateTime> { pub fn checked_add_months(self, rhs: Months) -> Option<NaiveDateTime> {
Some(Self { date: self.date.checked_add_months(rhs)?, time: self.time }) Some(Self { date: self.date.checked_add_months(rhs)?, time: self.time })
} }
@ -704,6 +717,7 @@ impl NaiveDateTime {
/// assert_eq!(leap.checked_sub_signed(TimeDelta::days(1)), /// assert_eq!(leap.checked_sub_signed(TimeDelta::days(1)),
/// Some(from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap())); /// Some(from_ymd(2016, 7, 7).and_hms_milli_opt(3, 6, 0, 300).unwrap()));
/// ``` /// ```
#[must_use]
pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option<NaiveDateTime> { pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option<NaiveDateTime> {
let (time, rhs) = self.time.overflowing_sub_signed(rhs); let (time, rhs) = self.time.overflowing_sub_signed(rhs);
@ -740,6 +754,7 @@ impl NaiveDateTime {
/// None /// None
/// ); /// );
/// ``` /// ```
#[must_use]
pub fn checked_sub_months(self, rhs: Months) -> Option<NaiveDateTime> { pub fn checked_sub_months(self, rhs: Months) -> Option<NaiveDateTime> {
Some(Self { date: self.date.checked_sub_months(rhs)?, time: self.time }) Some(Self { date: self.date.checked_sub_months(rhs)?, time: self.time })
} }
@ -747,6 +762,7 @@ impl NaiveDateTime {
/// Add a duration in [`Days`] to the date part of the `NaiveDateTime` /// Add a duration in [`Days`] to the date part of the `NaiveDateTime`
/// ///
/// Returns `None` if the resulting date would be out of range. /// Returns `None` if the resulting date would be out of range.
#[must_use]
pub fn checked_add_days(self, days: Days) -> Option<Self> { pub fn checked_add_days(self, days: Days) -> Option<Self> {
Some(Self { date: self.date.checked_add_days(days)?, ..self }) Some(Self { date: self.date.checked_add_days(days)?, ..self })
} }
@ -754,6 +770,7 @@ impl NaiveDateTime {
/// Subtract a duration in [`Days`] from the date part of the `NaiveDateTime` /// Subtract a duration in [`Days`] from the date part of the `NaiveDateTime`
/// ///
/// Returns `None` if the resulting date would be out of range. /// Returns `None` if the resulting date would be out of range.
#[must_use]
pub fn checked_sub_days(self, days: Days) -> Option<Self> { pub fn checked_sub_days(self, days: Days) -> Option<Self> {
Some(Self { date: self.date.checked_sub_days(days)?, ..self }) Some(Self { date: self.date.checked_sub_days(days)?, ..self })
} }
@ -796,6 +813,7 @@ impl NaiveDateTime {
/// assert_eq!(from_ymd(2015, 7, 1).and_hms_opt(1, 0, 0).unwrap().signed_duration_since(leap), /// assert_eq!(from_ymd(2015, 7, 1).and_hms_opt(1, 0, 0).unwrap().signed_duration_since(leap),
/// TimeDelta::seconds(3600) - TimeDelta::milliseconds(500)); /// TimeDelta::seconds(3600) - TimeDelta::milliseconds(500));
/// ``` /// ```
#[must_use]
pub fn signed_duration_since(self, rhs: NaiveDateTime) -> TimeDelta { pub fn signed_duration_since(self, rhs: NaiveDateTime) -> TimeDelta {
self.date.signed_duration_since(rhs.date) + self.time.signed_duration_since(rhs.time) self.date.signed_duration_since(rhs.date) + self.time.signed_duration_since(rhs.time)
} }
@ -830,6 +848,7 @@ impl NaiveDateTime {
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline] #[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where where
I: Iterator<Item = B> + Clone, I: Iterator<Item = B> + Clone,
@ -873,6 +892,7 @@ impl NaiveDateTime {
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline] #[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt)) self.format_with_items(StrftimeItems::new(fmt))
} }
@ -894,6 +914,7 @@ impl NaiveDateTime {
/// use chrono::{NaiveDate, Utc}; /// use chrono::{NaiveDate, Utc};
/// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap().and_local_timezone(Utc).unwrap(); /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap().and_local_timezone(Utc).unwrap();
/// assert_eq!(dt.timezone(), Utc); /// assert_eq!(dt.timezone(), Utc);
#[must_use]
pub fn and_local_timezone<Tz: TimeZone>(&self, tz: Tz) -> LocalResult<DateTime<Tz>> { pub fn and_local_timezone<Tz: TimeZone>(&self, tz: Tz) -> LocalResult<DateTime<Tz>> {
tz.from_local_datetime(self) tz.from_local_datetime(self)
} }

View File

@ -110,6 +110,7 @@ pub mod ts_nanoseconds {
/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -136,6 +137,7 @@ pub mod ts_nanoseconds {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -230,6 +232,7 @@ pub mod ts_nanoseconds_option {
/// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -259,6 +262,7 @@ pub mod ts_nanoseconds_option {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -356,6 +360,7 @@ pub mod ts_microseconds {
/// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -382,6 +387,7 @@ pub mod ts_microseconds {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -479,6 +485,7 @@ pub mod ts_microseconds_option {
/// assert_eq!(as_string, r#"{"time":1526522699918355}"#); /// assert_eq!(as_string, r#"{"time":1526522699918355}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -508,6 +515,7 @@ pub mod ts_microseconds_option {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -605,6 +613,7 @@ pub mod ts_milliseconds {
/// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -631,6 +640,7 @@ pub mod ts_milliseconds {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -725,6 +735,7 @@ pub mod ts_milliseconds_option {
/// assert_eq!(as_string, r#"{"time":1526522699918}"#); /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -754,6 +765,7 @@ pub mod ts_milliseconds_option {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -851,6 +863,7 @@ pub mod ts_seconds {
/// assert_eq!(as_string, r#"{"time":1431684000}"#); /// assert_eq!(as_string, r#"{"time":1431684000}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -877,6 +890,7 @@ pub mod ts_seconds {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
@ -968,6 +982,7 @@ pub mod ts_seconds_option {
/// assert_eq!(as_string, r#"{"time":1526522699}"#); /// assert_eq!(as_string, r#"{"time":1526522699}"#);
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(opt: &Option<NaiveDateTime>, serializer: S) -> Result<S::Ok, S::Error>
where where
S: ser::Serializer, S: ser::Serializer,
@ -997,6 +1012,7 @@ pub mod ts_seconds_option {
/// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
/// # Ok::<(), serde_json::Error>(()) /// # Ok::<(), serde_json::Error>(())
/// ``` /// ```
#[must_use]
pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error> pub fn deserialize<'de, D>(d: D) -> Result<Option<NaiveDateTime>, D::Error>
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,

View File

@ -115,6 +115,7 @@ impl YearFlags {
#[allow(unreachable_pub)] // public as an alias for benchmarks only #[allow(unreachable_pub)] // public as an alias for benchmarks only
#[doc(hidden)] // for benchmarks only #[doc(hidden)] // for benchmarks only
#[inline] #[inline]
#[must_use]
pub fn from_year(year: i32) -> YearFlags { pub fn from_year(year: i32) -> YearFlags {
let year = mod_floor(year, 400); let year = mod_floor(year, 400);
YearFlags::from_year_mod_400(year) YearFlags::from_year_mod_400(year)

View File

@ -210,6 +210,7 @@ impl NaiveTime {
/// Panics on invalid hour, minute and/or second. /// Panics on invalid hour, minute and/or second.
#[deprecated(since = "0.4.23", note = "use `from_hms_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_hms_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime { pub fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime {
NaiveTime::from_hms_opt(hour, min, sec).expect("invalid time") NaiveTime::from_hms_opt(hour, min, sec).expect("invalid time")
} }
@ -235,6 +236,7 @@ impl NaiveTime {
/// assert!(from_hms_opt(23, 59, 60).is_none()); /// assert!(from_hms_opt(23, 59, 60).is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub const fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option<NaiveTime> { pub const fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option<NaiveTime> {
NaiveTime::from_hms_nano_opt(hour, min, sec, 0) NaiveTime::from_hms_nano_opt(hour, min, sec, 0)
} }
@ -247,6 +249,7 @@ impl NaiveTime {
/// Panics on invalid hour, minute, second and/or millisecond. /// Panics on invalid hour, minute, second and/or millisecond.
#[deprecated(since = "0.4.23", note = "use `from_hms_milli_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_hms_milli_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> NaiveTime { pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> NaiveTime {
NaiveTime::from_hms_milli_opt(hour, min, sec, milli).expect("invalid time") NaiveTime::from_hms_milli_opt(hour, min, sec, milli).expect("invalid time")
} }
@ -274,6 +277,7 @@ impl NaiveTime {
/// assert!(from_hmsm_opt(23, 59, 59, 2_000).is_none()); /// assert!(from_hmsm_opt(23, 59, 59, 2_000).is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn from_hms_milli_opt(hour: u32, min: u32, sec: u32, milli: u32) -> Option<NaiveTime> { pub fn from_hms_milli_opt(hour: u32, min: u32, sec: u32, milli: u32) -> Option<NaiveTime> {
milli milli
.checked_mul(1_000_000) .checked_mul(1_000_000)
@ -288,6 +292,7 @@ impl NaiveTime {
/// Panics on invalid hour, minute, second and/or microsecond. /// Panics on invalid hour, minute, second and/or microsecond.
#[deprecated(since = "0.4.23", note = "use `from_hms_micro_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_hms_micro_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> NaiveTime { pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> NaiveTime {
NaiveTime::from_hms_micro_opt(hour, min, sec, micro).expect("invalid time") NaiveTime::from_hms_micro_opt(hour, min, sec, micro).expect("invalid time")
} }
@ -315,6 +320,7 @@ impl NaiveTime {
/// assert!(from_hmsu_opt(23, 59, 59, 2_000_000).is_none()); /// assert!(from_hmsu_opt(23, 59, 59, 2_000_000).is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn from_hms_micro_opt(hour: u32, min: u32, sec: u32, micro: u32) -> Option<NaiveTime> { pub fn from_hms_micro_opt(hour: u32, min: u32, sec: u32, micro: u32) -> Option<NaiveTime> {
micro.checked_mul(1_000).and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano)) micro.checked_mul(1_000).and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano))
} }
@ -327,6 +333,7 @@ impl NaiveTime {
/// Panics on invalid hour, minute, second and/or nanosecond. /// Panics on invalid hour, minute, second and/or nanosecond.
#[deprecated(since = "0.4.23", note = "use `from_hms_nano_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_hms_nano_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> NaiveTime { pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> NaiveTime {
NaiveTime::from_hms_nano_opt(hour, min, sec, nano).expect("invalid time") NaiveTime::from_hms_nano_opt(hour, min, sec, nano).expect("invalid time")
} }
@ -354,6 +361,7 @@ impl NaiveTime {
/// assert!(from_hmsn_opt(23, 59, 59, 2_000_000_000).is_none()); /// assert!(from_hmsn_opt(23, 59, 59, 2_000_000_000).is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub const fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option<NaiveTime> { pub const fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option<NaiveTime> {
if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 {
return None; return None;
@ -370,6 +378,7 @@ impl NaiveTime {
/// Panics on invalid number of seconds and/or nanosecond. /// Panics on invalid number of seconds and/or nanosecond.
#[deprecated(since = "0.4.23", note = "use `from_num_seconds_from_midnight_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `from_num_seconds_from_midnight_opt()` instead")]
#[inline] #[inline]
#[must_use]
pub fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> NaiveTime { pub fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> NaiveTime {
NaiveTime::from_num_seconds_from_midnight_opt(secs, nano).expect("invalid time") NaiveTime::from_num_seconds_from_midnight_opt(secs, nano).expect("invalid time")
} }
@ -395,6 +404,7 @@ impl NaiveTime {
/// assert!(from_nsecs_opt(86399, 2_000_000_000).is_none()); /// assert!(from_nsecs_opt(86399, 2_000_000_000).is_none());
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub const fn from_num_seconds_from_midnight_opt(secs: u32, nano: u32) -> Option<NaiveTime> { pub const fn from_num_seconds_from_midnight_opt(secs: u32, nano: u32) -> Option<NaiveTime> {
if secs >= 86_400 || nano >= 2_000_000_000 { if secs >= 86_400 || nano >= 2_000_000_000 {
return None; return None;
@ -488,6 +498,7 @@ impl NaiveTime {
/// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::hours(-7)), /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(TimeDelta::hours(-7)),
/// (from_hms(20, 4, 5), -86_400)); /// (from_hms(20, 4, 5), -86_400));
/// ``` /// ```
#[must_use]
pub fn overflowing_add_signed(&self, mut rhs: TimeDelta) -> (NaiveTime, i64) { pub fn overflowing_add_signed(&self, mut rhs: TimeDelta) -> (NaiveTime, i64) {
let mut secs = self.secs; let mut secs = self.secs;
let mut frac = self.frac; let mut frac = self.frac;
@ -571,6 +582,7 @@ impl NaiveTime {
/// (from_hms(1, 4, 5), -86_400)); /// (from_hms(1, 4, 5), -86_400));
/// ``` /// ```
#[inline] #[inline]
#[must_use]
pub fn overflowing_sub_signed(&self, rhs: TimeDelta) -> (NaiveTime, i64) { pub fn overflowing_sub_signed(&self, rhs: TimeDelta) -> (NaiveTime, i64) {
let (time, rhs) = self.overflowing_add_signed(-rhs); let (time, rhs) = self.overflowing_add_signed(-rhs);
(time, -rhs) // safe to negate, rhs is within +/- (2^63 / 1000) (time, -rhs) // safe to negate, rhs is within +/- (2^63 / 1000)
@ -630,6 +642,7 @@ impl NaiveTime {
/// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(2, 59, 59, 1_000)), /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(2, 59, 59, 1_000)),
/// TimeDelta::seconds(61)); /// TimeDelta::seconds(61));
/// ``` /// ```
#[must_use]
pub fn signed_duration_since(self, rhs: NaiveTime) -> TimeDelta { pub fn signed_duration_since(self, rhs: NaiveTime) -> TimeDelta {
// | | :leap| | | | | | | :leap| | // | | :leap| | | | | | | :leap| |
// | | : | | | | | | | : | | // | | : | | | | | | | : | |
@ -692,6 +705,7 @@ impl NaiveTime {
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline] #[inline]
#[must_use]
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I> pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where where
I: Iterator<Item = B> + Clone, I: Iterator<Item = B> + Clone,
@ -737,6 +751,7 @@ impl NaiveTime {
#[cfg(any(feature = "alloc", feature = "std", test))] #[cfg(any(feature = "alloc", feature = "std", test))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
#[inline] #[inline]
#[must_use]
pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> { pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt)) self.format_with_items(StrftimeItems::new(fmt))
} }

View File

@ -34,6 +34,7 @@ impl FixedOffset {
/// ///
/// Panics on the out-of-bound `secs`. /// Panics on the out-of-bound `secs`.
#[deprecated(since = "0.4.23", note = "use `east_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `east_opt()` instead")]
#[must_use]
pub fn east(secs: i32) -> FixedOffset { pub fn east(secs: i32) -> FixedOffset {
FixedOffset::east_opt(secs).expect("FixedOffset::east out of bounds") FixedOffset::east_opt(secs).expect("FixedOffset::east out of bounds")
} }
@ -52,6 +53,7 @@ impl FixedOffset {
/// .and_hms_opt(0, 0, 0).unwrap(); /// .and_hms_opt(0, 0, 0).unwrap();
/// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00") /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00")
/// ``` /// ```
#[must_use]
pub const fn east_opt(secs: i32) -> Option<FixedOffset> { pub const fn east_opt(secs: i32) -> Option<FixedOffset> {
if -86_400 < secs && secs < 86_400 { if -86_400 < secs && secs < 86_400 {
Some(FixedOffset { local_minus_utc: secs }) Some(FixedOffset { local_minus_utc: secs })
@ -65,6 +67,7 @@ impl FixedOffset {
/// ///
/// Panics on the out-of-bound `secs`. /// Panics on the out-of-bound `secs`.
#[deprecated(since = "0.4.23", note = "use `west_opt()` instead")] #[deprecated(since = "0.4.23", note = "use `west_opt()` instead")]
#[must_use]
pub fn west(secs: i32) -> FixedOffset { pub fn west(secs: i32) -> FixedOffset {
FixedOffset::west_opt(secs).expect("FixedOffset::west out of bounds") FixedOffset::west_opt(secs).expect("FixedOffset::west out of bounds")
} }
@ -83,6 +86,7 @@ impl FixedOffset {
/// .and_hms_opt(0, 0, 0).unwrap(); /// .and_hms_opt(0, 0, 0).unwrap();
/// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00") /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00")
/// ``` /// ```
#[must_use]
pub const fn west_opt(secs: i32) -> Option<FixedOffset> { pub const fn west_opt(secs: i32) -> Option<FixedOffset> {
if -86_400 < secs && secs < 86_400 { if -86_400 < secs && secs < 86_400 {
Some(FixedOffset { local_minus_utc: -secs }) Some(FixedOffset { local_minus_utc: -secs })

View File

@ -60,6 +60,7 @@ impl Local {
/// Returns a `Date` which corresponds to the current date. /// Returns a `Date` which corresponds to the current date.
#[deprecated(since = "0.4.23", note = "use `Local::now()` instead")] #[deprecated(since = "0.4.23", note = "use `Local::now()` instead")]
#[allow(deprecated)] #[allow(deprecated)]
#[must_use]
pub fn today() -> Date<Local> { pub fn today() -> Date<Local> {
Local::now().date() Local::now().date()
} }
@ -70,6 +71,7 @@ impl Local {
feature = "wasmbind", feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi")) not(any(target_os = "emscripten", target_os = "wasi"))
)))] )))]
#[must_use]
pub fn now() -> DateTime<Local> { pub fn now() -> DateTime<Local> {
inner::now() inner::now()
} }
@ -80,6 +82,7 @@ impl Local {
feature = "wasmbind", feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi")) not(any(target_os = "emscripten", target_os = "wasi"))
))] ))]
#[must_use]
pub fn now() -> DateTime<Local> { pub fn now() -> DateTime<Local> {
use super::Utc; use super::Utc;
let now: DateTime<Utc> = super::Utc::now(); let now: DateTime<Utc> = super::Utc::now();

View File

@ -100,21 +100,6 @@ impl From<Utf8Error> for Error {
} }
} }
// MSRV: 1.38
#[inline]
const fn rem_euclid(v: i64, rhs: i64) -> i64 {
let r = v % rhs;
if r < 0 {
if rhs < 0 {
r - rhs
} else {
r + rhs
}
} else {
r
}
}
/// Number of hours in one day /// Number of hours in one day
const HOURS_PER_DAY: i64 = 24; const HOURS_PER_DAY: i64 = 24;
/// Number of seconds in one hour /// Number of seconds in one hour

View File

@ -7,7 +7,6 @@ use super::rule::TransitionRule;
use super::timezone::{LeapSecond, LocalTimeType, TimeZone, Transition}; use super::timezone::{LeapSecond, LocalTimeType, TimeZone, Transition};
use super::Error; use super::Error;
#[allow(clippy::map_clone)] // MSRV: 1.36
pub(super) fn parse(bytes: &[u8]) -> Result<TimeZone, Error> { pub(super) fn parse(bytes: &[u8]) -> Result<TimeZone, Error> {
let mut cursor = Cursor::new(bytes); let mut cursor = Cursor::new(bytes);
let state = State::new(&mut cursor, true)?; let state = State::new(&mut cursor, true)?;
@ -66,8 +65,8 @@ pub(super) fn parse(bytes: &[u8]) -> Result<TimeZone, Error> {
leap_seconds.push(LeapSecond::new(unix_leap_time, correction)); leap_seconds.push(LeapSecond::new(unix_leap_time, correction));
} }
let std_walls_iter = state.std_walls.iter().map(|&i| i).chain(iter::repeat(0)); let std_walls_iter = state.std_walls.iter().copied().chain(iter::repeat(0));
let ut_locals_iter = state.ut_locals.iter().map(|&i| i).chain(iter::repeat(0)); let ut_locals_iter = state.ut_locals.iter().copied().chain(iter::repeat(0));
if std_walls_iter.zip(ut_locals_iter).take(state.header.type_count).any(|pair| pair == (0, 1)) { if std_walls_iter.zip(ut_locals_iter).take(state.header.type_count).any(|pair| pair == (0, 1)) {
return Err(Error::InvalidTzFile( return Err(Error::InvalidTzFile(
"invalid couple of standard/wall and UT/local indicators", "invalid couple of standard/wall and UT/local indicators",

View File

@ -3,7 +3,7 @@ use std::cmp::Ordering;
use super::parser::Cursor; use super::parser::Cursor;
use super::timezone::{LocalTimeType, SECONDS_PER_WEEK}; use super::timezone::{LocalTimeType, SECONDS_PER_WEEK};
use super::{ use super::{
rem_euclid, Error, CUMUL_DAY_IN_MONTHS_NORMAL_YEAR, DAYS_PER_WEEK, DAY_IN_MONTHS_NORMAL_YEAR, Error, CUMUL_DAY_IN_MONTHS_NORMAL_YEAR, DAYS_PER_WEEK, DAY_IN_MONTHS_NORMAL_YEAR,
SECONDS_PER_DAY, SECONDS_PER_DAY,
}; };
@ -589,9 +589,9 @@ impl RuleDay {
} }
let week_day_of_first_month_day = let week_day_of_first_month_day =
rem_euclid(4 + days_since_unix_epoch(year, month, 1), DAYS_PER_WEEK); (4 + days_since_unix_epoch(year, month, 1)).rem_euclid(DAYS_PER_WEEK);
let first_week_day_occurence_in_month = let first_week_day_occurence_in_month =
1 + rem_euclid(week_day as i64 - week_day_of_first_month_day, DAYS_PER_WEEK); 1 + (week_day as i64 - week_day_of_first_month_day).rem_euclid(DAYS_PER_WEEK);
let mut month_day = let mut month_day =
first_week_day_occurence_in_month + (week as i64 - 1) * DAYS_PER_WEEK; first_week_day_occurence_in_month + (week as i64 - 1) * DAYS_PER_WEEK;
@ -777,7 +777,6 @@ mod tests {
use super::super::timezone::Transition; use super::super::timezone::Transition;
use super::super::{Error, TimeZone}; use super::super::{Error, TimeZone};
use super::{AlternateTime, LocalTimeType, RuleDay, TransitionRule}; use super::{AlternateTime, LocalTimeType, RuleDay, TransitionRule};
use crate::matches;
#[test] #[test]
fn test_quoted() -> Result<(), Error> { fn test_quoted() -> Result<(), Error> {

View File

@ -620,8 +620,8 @@ const fn saturating_abs(v: i32) -> i32 {
// Possible system timezone directories // Possible system timezone directories
#[cfg(unix)] #[cfg(unix)]
const ZONE_INFO_DIRECTORIES: [&str; 3] = const ZONE_INFO_DIRECTORIES: [&str; 4] =
["/usr/share/zoneinfo", "/share/zoneinfo", "/etc/zoneinfo"]; ["/usr/share/zoneinfo", "/share/zoneinfo", "/etc/zoneinfo", "/usr/share/lib/zoneinfo"];
/// Number of seconds in one week /// Number of seconds in one week
pub(crate) const SECONDS_PER_WEEK: i64 = SECONDS_PER_DAY * DAYS_PER_WEEK; pub(crate) const SECONDS_PER_WEEK: i64 = SECONDS_PER_DAY * DAYS_PER_WEEK;
@ -632,7 +632,6 @@ const SECONDS_PER_28_DAYS: i64 = SECONDS_PER_DAY * 28;
mod tests { mod tests {
use super::super::Error; use super::super::Error;
use super::{LeapSecond, LocalTimeType, TimeZone, TimeZoneName, Transition, TransitionRule}; use super::{LeapSecond, LocalTimeType, TimeZone, TimeZoneName, Transition, TransitionRule};
use crate::matches;
#[test] #[test]
fn test_no_dst() -> Result<(), Error> { fn test_no_dst() -> Result<(), Error> {

View File

@ -8,15 +8,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::io; use core::mem::MaybeUninit;
use std::mem; use std::io::Error;
use std::ptr; use std::ptr;
use std::time::{SystemTime, UNIX_EPOCH}; use std::result::Result;
use windows_sys::Win32::Foundation::FILETIME; use windows_sys::Win32::Foundation::FILETIME;
use windows_sys::Win32::Foundation::SYSTEMTIME; use windows_sys::Win32::Foundation::SYSTEMTIME;
use windows_sys::Win32::System::Time::FileTimeToSystemTime; use windows_sys::Win32::System::SystemInformation::GetLocalTime;
use windows_sys::Win32::System::Time::GetTimeZoneInformation;
use windows_sys::Win32::System::Time::SystemTimeToFileTime; use windows_sys::Win32::System::Time::SystemTimeToFileTime;
use windows_sys::Win32::System::Time::SystemTimeToTzSpecificLocalTime; use windows_sys::Win32::System::Time::SystemTimeToTzSpecificLocalTime;
use windows_sys::Win32::System::Time::TzSpecificLocalTimeToSystemTime; use windows_sys::Win32::System::Time::TzSpecificLocalTimeToSystemTime;
@ -24,268 +23,143 @@ use windows_sys::Win32::System::Time::TzSpecificLocalTimeToSystemTime;
use super::{FixedOffset, Local}; use super::{FixedOffset, Local};
use crate::{DateTime, Datelike, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike}; use crate::{DateTime, Datelike, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
pub(super) fn now() -> DateTime<Local> { /// This macro calls a Windows API FFI and checks whether the function errored with the provided error_id. If an error returns,
let datetime = tm_to_datetime(Timespec::now().local()); /// the macro will return an `Error::last_os_error()`.
datetime.single().expect("invalid time")
}
/// Converts a local `NaiveDateTime` to the `time::Timespec`.
pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> {
let tm = Tm {
tm_sec: d.second() as i32,
tm_min: d.minute() as i32,
tm_hour: d.hour() as i32,
tm_mday: d.day() as i32,
tm_mon: d.month0() as i32, // yes, C is that strange...
tm_year: d.year() - 1900, // this doesn't underflow, we know that d is `NaiveDateTime`.
tm_wday: 0, // to_local ignores this
tm_yday: 0, // and this
tm_isdst: -1,
// This seems pretty fake?
tm_utcoff: i32::from(local),
// do not set this, OS APIs are heavily inconsistent in terms of leap second handling
tm_nsec: 0,
};
let spec = Timespec {
sec: match local {
false => utc_tm_to_time(&tm),
true => local_tm_to_time(&tm),
},
nsec: tm.tm_nsec,
};
// Adjust for leap seconds
let mut tm = spec.local();
assert_eq!(tm.tm_nsec, 0);
tm.tm_nsec = d.nanosecond() as i32;
tm_to_datetime(tm)
}
/// Converts a `time::Tm` struct into the timezone-aware `DateTime`.
fn tm_to_datetime(mut tm: Tm) -> LocalResult<DateTime<Local>> {
if tm.tm_sec >= 60 {
tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000;
tm.tm_sec = 59;
}
let date = NaiveDate::from_ymd_opt(tm.tm_year + 1900, tm.tm_mon as u32 + 1, tm.tm_mday as u32)
.unwrap();
let time = NaiveTime::from_hms_nano_opt(
tm.tm_hour as u32,
tm.tm_min as u32,
tm.tm_sec as u32,
tm.tm_nsec as u32,
);
match time {
Some(time) => {
let offset = FixedOffset::east_opt(tm.tm_utcoff).unwrap();
let datetime = DateTime::from_utc(date.and_time(time) - offset, offset);
// #TODO - there should be ambiguous cases, investigate?
LocalResult::Single(datetime)
}
None => LocalResult::None,
}
}
/// A record specifying a time value in seconds and nanoseconds, where
/// nanoseconds represent the offset from the given second.
/// ///
/// For example a timespec of 1.2 seconds after the beginning of the epoch would /// # Safety
/// be represented as {sec: 1, nsec: 200000000}.
struct Timespec {
sec: i64,
nsec: i32,
}
impl Timespec {
/// Constructs a timespec representing the current time in UTC.
fn now() -> Timespec {
let st =
SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch");
Timespec { sec: st.as_secs() as i64, nsec: st.subsec_nanos() as i32 }
}
/// Converts this timespec into the system's local time.
fn local(self) -> Tm {
let mut tm = Tm {
tm_sec: 0,
tm_min: 0,
tm_hour: 0,
tm_mday: 0,
tm_mon: 0,
tm_year: 0,
tm_wday: 0,
tm_yday: 0,
tm_isdst: 0,
tm_utcoff: 0,
tm_nsec: 0,
};
time_to_local_tm(self.sec, &mut tm);
tm.tm_nsec = self.nsec;
tm
}
}
/// Holds a calendar date and time broken down into its components (year, month,
/// day, and so on), also called a broken-down time value.
// FIXME: use c_int instead of i32?
#[repr(C)]
struct Tm {
/// Seconds after the minute - [0, 60]
tm_sec: i32,
/// Minutes after the hour - [0, 59]
tm_min: i32,
/// Hours after midnight - [0, 23]
tm_hour: i32,
/// Day of the month - [1, 31]
tm_mday: i32,
/// Months since January - [0, 11]
tm_mon: i32,
/// Years since 1900
tm_year: i32,
/// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday.
tm_wday: i32,
/// Days since January 1 - [0, 365]
tm_yday: i32,
/// Daylight Saving Time flag.
/// ///
/// This value is positive if Daylight Saving Time is in effect, zero if /// The provided error ID must align with the provided Windows API, providing the wrong ID could lead to UB.
/// Daylight Saving Time is not in effect, and negative if this information macro_rules! windows_sys_call {
/// is not available. ($name:ident($($arg:expr),*), $error_id:expr) => {
tm_isdst: i32, if $name($($arg),*) == $error_id {
return Err(Error::last_os_error());
/// Identifies the time zone that was used to compute this broken-down time }
/// value, including any adjustment for Daylight Saving Time. This is the }
/// number of seconds east of UTC. For example, for U.S. Pacific Daylight
/// Time, the value is `-7*60*60 = -25200`.
tm_utcoff: i32,
/// Nanoseconds after the second - [0, 10<sup>9</sup> - 1]
tm_nsec: i32,
} }
const HECTONANOSECS_IN_SEC: i64 = 10_000_000; const HECTONANOSECS_IN_SEC: i64 = 10_000_000;
const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC; const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC;
fn time_to_file_time(sec: i64) -> FILETIME { pub(super) fn now() -> DateTime<Local> {
let t = ((sec * HECTONANOSECS_IN_SEC) + HECTONANOSEC_TO_UNIX_EPOCH) as u64; LocalSysTime::local().datetime()
FILETIME { dwLowDateTime: t as u32, dwHighDateTime: (t >> 32) as u32 }
} }
fn file_time_as_u64(ft: &FILETIME) -> u64 { /// Converts a local `NaiveDateTime` to the `time::Timespec`.
((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64) pub(super) fn naive_to_local(d: &NaiveDateTime, local: bool) -> LocalResult<DateTime<Local>> {
} let naive_sys_time = system_time_from_naive_date_time(d);
fn file_time_to_unix_seconds(ft: &FILETIME) -> i64 { let local_sys_time = match local {
let t = file_time_as_u64(ft) as i64; false => LocalSysTime::from_utc_time(naive_sys_time),
((t - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC) as i64 true => LocalSysTime::from_local_time(naive_sys_time),
}
fn system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME {
unsafe {
let mut ft = mem::zeroed();
SystemTimeToFileTime(sys, &mut ft);
ft
}
}
fn tm_to_system_time(tm: &Tm) -> SYSTEMTIME {
let mut sys: SYSTEMTIME = unsafe { mem::zeroed() };
sys.wSecond = tm.tm_sec as u16;
sys.wMinute = tm.tm_min as u16;
sys.wHour = tm.tm_hour as u16;
sys.wDay = tm.tm_mday as u16;
sys.wDayOfWeek = tm.tm_wday as u16;
sys.wMonth = (tm.tm_mon + 1) as u16;
sys.wYear = (tm.tm_year + 1900) as u16;
sys
}
fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) {
tm.tm_sec = sys.wSecond as i32;
tm.tm_min = sys.wMinute as i32;
tm.tm_hour = sys.wHour as i32;
tm.tm_mday = sys.wDay as i32;
tm.tm_wday = sys.wDayOfWeek as i32;
tm.tm_mon = (sys.wMonth - 1) as i32;
tm.tm_year = (sys.wYear - 1900) as i32;
tm.tm_yday = yday(tm.tm_year, tm.tm_mon + 1, tm.tm_mday);
fn yday(year: i32, month: i32, day: i32) -> i32 {
let leap = if month > 2 {
if year % 4 == 0 {
1
} else {
2
}
} else {
0
}; };
let july = i32::from(month > 7);
(month - 1) * 30 + month / 2 + (day - 1) - leap + july if let Ok(local) = local_sys_time {
return LocalResult::Single(local.datetime());
}
LocalResult::None
}
struct LocalSysTime {
inner: SYSTEMTIME,
offset: i32,
}
impl LocalSysTime {
fn local() -> Self {
let mut now = MaybeUninit::<SYSTEMTIME>::uninit();
unsafe { GetLocalTime(now.as_mut_ptr()) }
// SAFETY: GetLocalTime cannot fail according to spec, so we can assume the value
// is initialized.
let st = unsafe { now.assume_init() };
Self::from_local_time(st).expect("Current local time must exist")
}
fn from_utc_time(utc_time: SYSTEMTIME) -> Result<Self, Error> {
let local_time = utc_to_local_time(&utc_time)?;
let utc_secs = system_time_as_unix_seconds(&utc_time)?;
let local_secs = system_time_as_unix_seconds(&local_time)?;
let offset = (local_secs - utc_secs) as i32;
Ok(Self { inner: local_time, offset })
}
fn from_local_time(local_time: SYSTEMTIME) -> Result<Self, Error> {
let utc_time = local_to_utc_time(&local_time)?;
let utc_secs = system_time_as_unix_seconds(&utc_time)?;
let local_secs = system_time_as_unix_seconds(&local_time)?;
let offset = (local_secs - utc_secs) as i32;
Ok(Self { inner: local_time, offset })
}
fn datetime(self) -> DateTime<Local> {
let st = self.inner;
let date =
NaiveDate::from_ymd_opt(st.wYear as i32, st.wMonth as u32, st.wDay as u32).unwrap();
let time = NaiveTime::from_hms(st.wHour as u32, st.wMinute as u32, st.wSecond as u32);
let offset = FixedOffset::east_opt(self.offset).unwrap();
DateTime::from_utc(date.and_time(time) - offset, offset)
} }
} }
macro_rules! call { fn system_time_from_naive_date_time(dt: &NaiveDateTime) -> SYSTEMTIME {
($name:ident($($arg:expr),*)) => { SYSTEMTIME {
if $name($($arg),*) == 0 { // Valid values: 1601-30827
panic!(concat!(stringify!($name), " failed with: {}"), wYear: dt.year() as u16,
io::Error::last_os_error()); // Valid values:1-12
} wMonth: dt.month() as u16,
// Valid values: 0-6, starting Sunday.
// NOTE: enum returns 1-7, starting Monday, so we are
// off here, but this is not currently used in local.
wDayOfWeek: dt.weekday() as u16,
// Valid values: 1-31
wDay: dt.day() as u16,
// Valid values: 0-23
wHour: dt.hour() as u16,
// Valid values: 0-59
wMinute: dt.minute() as u16,
// Valid values: 0-59
wSecond: dt.second() as u16,
// Valid values: 0-999
wMilliseconds: 0,
} }
} }
fn time_to_local_tm(sec: i64, tm: &mut Tm) { pub(crate) fn local_to_utc_time(local: &SYSTEMTIME) -> Result<SYSTEMTIME, Error> {
let ft = time_to_file_time(sec); let mut sys_time = MaybeUninit::<SYSTEMTIME>::uninit();
unsafe { unsafe {
let mut utc = mem::zeroed(); windows_sys_call!(
let mut local = mem::zeroed(); TzSpecificLocalTimeToSystemTime(ptr::null(), local, sys_time.as_mut_ptr()),
call!(FileTimeToSystemTime(&ft, &mut utc)); 0
call!(SystemTimeToTzSpecificLocalTime(ptr::null(), &utc, &mut local)); )
system_time_to_tm(&local, tm); };
// SAFETY: TzSpecificLocalTimeToSystemTime must have succeeded at this point, so we can
let local = system_time_to_file_time(&local); // assume the value is initialized.
let local_sec = file_time_to_unix_seconds(&local); Ok(unsafe { sys_time.assume_init() })
let mut tz = mem::zeroed();
GetTimeZoneInformation(&mut tz);
// SystemTimeToTzSpecificLocalTime already applied the biases so
// check if it non standard
tm.tm_utcoff = (local_sec - sec) as i32;
tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) { 0 } else { 1 };
}
} }
fn utc_tm_to_time(tm: &Tm) -> i64 { pub(crate) fn utc_to_local_time(utc_time: &SYSTEMTIME) -> Result<SYSTEMTIME, Error> {
let mut local = MaybeUninit::<SYSTEMTIME>::uninit();
unsafe { unsafe {
let mut ft = mem::zeroed(); windows_sys_call!(
let sys_time = tm_to_system_time(tm); SystemTimeToTzSpecificLocalTime(ptr::null(), utc_time, local.as_mut_ptr()),
call!(SystemTimeToFileTime(&sys_time, &mut ft)); 0
file_time_to_unix_seconds(&ft) )
} };
// SAFETY: SystemTimeToTzSpecificLocalTime must have succeeded at this point, so we can
// assume the value is initialized.
Ok(unsafe { local.assume_init() })
} }
fn local_tm_to_time(tm: &Tm) -> i64 { /// Returns a i64 value representing the unix seconds conversion of the current `WinSystemTime`.
unsafe { pub(crate) fn system_time_as_unix_seconds(st: &SYSTEMTIME) -> Result<i64, Error> {
let mut ft = mem::zeroed(); let mut init = MaybeUninit::<FILETIME>::uninit();
let mut utc = mem::zeroed(); unsafe { windows_sys_call!(SystemTimeToFileTime(st, init.as_mut_ptr()), 0) }
let sys_time = tm_to_system_time(tm); // SystemTimeToFileTime must have succeeded at this point, so we can assum the value is
call!(TzSpecificLocalTimeToSystemTime(ptr::null(), &sys_time, &mut utc)); // initalized.
call!(SystemTimeToFileTime(&utc, &mut ft)); let filetime = unsafe { init.assume_init() };
file_time_to_unix_seconds(&ft) let bit_shift = ((filetime.dwHighDateTime as u64) << 32) | (filetime.dwLowDateTime as u64);
} let unix_secs = (bit_shift as i64 - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC;
Ok(unix_secs)
} }

View File

@ -52,6 +52,7 @@ pub enum LocalResult<T> {
impl<T> LocalResult<T> { impl<T> LocalResult<T> {
/// Returns `Some` only when the conversion result is unique, or `None` otherwise. /// Returns `Some` only when the conversion result is unique, or `None` otherwise.
#[must_use]
pub fn single(self) -> Option<T> { pub fn single(self) -> Option<T> {
match self { match self {
LocalResult::Single(t) => Some(t), LocalResult::Single(t) => Some(t),
@ -60,6 +61,7 @@ impl<T> LocalResult<T> {
} }
/// Returns `Some` for the earliest possible conversion result, or `None` if none. /// Returns `Some` for the earliest possible conversion result, or `None` if none.
#[must_use]
pub fn earliest(self) -> Option<T> { pub fn earliest(self) -> Option<T> {
match self { match self {
LocalResult::Single(t) | LocalResult::Ambiguous(t, _) => Some(t), LocalResult::Single(t) | LocalResult::Ambiguous(t, _) => Some(t),
@ -68,6 +70,7 @@ impl<T> LocalResult<T> {
} }
/// Returns `Some` for the latest possible conversion result, or `None` if none. /// Returns `Some` for the latest possible conversion result, or `None` if none.
#[must_use]
pub fn latest(self) -> Option<T> { pub fn latest(self) -> Option<T> {
match self { match self {
LocalResult::Single(t) | LocalResult::Ambiguous(_, t) => Some(t), LocalResult::Single(t) | LocalResult::Ambiguous(_, t) => Some(t),
@ -76,6 +79,7 @@ impl<T> LocalResult<T> {
} }
/// Maps a `LocalResult<T>` into `LocalResult<U>` with given function. /// Maps a `LocalResult<T>` into `LocalResult<U>` with given function.
#[must_use]
pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> LocalResult<U> { pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> LocalResult<U> {
match self { match self {
LocalResult::None => LocalResult::None, LocalResult::None => LocalResult::None,
@ -92,6 +96,7 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> {
/// ///
/// Propagates any error. Ambiguous result would be discarded. /// Propagates any error. Ambiguous result would be discarded.
#[inline] #[inline]
#[must_use]
pub fn and_time(self, time: NaiveTime) -> LocalResult<DateTime<Tz>> { pub fn and_time(self, time: NaiveTime) -> LocalResult<DateTime<Tz>> {
match self { match self {
LocalResult::Single(d) => { LocalResult::Single(d) => {
@ -106,6 +111,7 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> {
/// ///
/// Propagates any error. Ambiguous result would be discarded. /// Propagates any error. Ambiguous result would be discarded.
#[inline] #[inline]
#[must_use]
pub fn and_hms_opt(self, hour: u32, min: u32, sec: u32) -> LocalResult<DateTime<Tz>> { pub fn and_hms_opt(self, hour: u32, min: u32, sec: u32) -> LocalResult<DateTime<Tz>> {
match self { match self {
LocalResult::Single(d) => { LocalResult::Single(d) => {
@ -121,6 +127,7 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> {
/// ///
/// Propagates any error. Ambiguous result would be discarded. /// Propagates any error. Ambiguous result would be discarded.
#[inline] #[inline]
#[must_use]
pub fn and_hms_milli_opt( pub fn and_hms_milli_opt(
self, self,
hour: u32, hour: u32,
@ -142,6 +149,7 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> {
/// ///
/// Propagates any error. Ambiguous result would be discarded. /// Propagates any error. Ambiguous result would be discarded.
#[inline] #[inline]
#[must_use]
pub fn and_hms_micro_opt( pub fn and_hms_micro_opt(
self, self,
hour: u32, hour: u32,
@ -163,6 +171,7 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> {
/// ///
/// Propagates any error. Ambiguous result would be discarded. /// Propagates any error. Ambiguous result would be discarded.
#[inline] #[inline]
#[must_use]
pub fn and_hms_nano_opt( pub fn and_hms_nano_opt(
self, self,
hour: u32, hour: u32,
@ -181,6 +190,8 @@ impl<Tz: TimeZone> LocalResult<Date<Tz>> {
impl<T: fmt::Debug> LocalResult<T> { impl<T: fmt::Debug> LocalResult<T> {
/// Returns the single unique conversion result, or panics accordingly. /// Returns the single unique conversion result, or panics accordingly.
#[must_use]
#[track_caller]
pub fn unwrap(self) -> T { pub fn unwrap(self) -> T {
match self { match self {
LocalResult::None => panic!("No such local time"), LocalResult::None => panic!("No such local time"),

View File

@ -54,6 +54,7 @@ impl Utc {
note = "use `Utc::now()` instead, potentially with `.date_naive()`" note = "use `Utc::now()` instead, potentially with `.date_naive()`"
)] )]
#[allow(deprecated)] #[allow(deprecated)]
#[must_use]
pub fn today() -> Date<Utc> { pub fn today() -> Date<Utc> {
Utc::now().date() Utc::now().date()
} }
@ -64,6 +65,7 @@ impl Utc {
feature = "wasmbind", feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi")) not(any(target_os = "emscripten", target_os = "wasi"))
)))] )))]
#[must_use]
pub fn now() -> DateTime<Utc> { pub fn now() -> DateTime<Utc> {
let now = let now =
SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch"); SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch");
@ -78,6 +80,7 @@ impl Utc {
feature = "wasmbind", feature = "wasmbind",
not(any(target_os = "emscripten", target_os = "wasi")) not(any(target_os = "emscripten", target_os = "wasi"))
))] ))]
#[must_use]
pub fn now() -> DateTime<Utc> { pub fn now() -> DateTime<Utc> {
let now = js_sys::Date::new_0(); let now = js_sys::Date::new_0();
DateTime::<Utc>::from(now) DateTime::<Utc>::from(now)

View File

@ -74,6 +74,7 @@ impl TimeDelta {
/// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks. /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks.
/// Panics when the duration is out of bounds. /// Panics when the duration is out of bounds.
#[inline] #[inline]
#[must_use]
pub fn weeks(weeks: i64) -> TimeDelta { pub fn weeks(weeks: i64) -> TimeDelta {
let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds"); let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds");
TimeDelta::seconds(secs) TimeDelta::seconds(secs)
@ -83,6 +84,7 @@ impl TimeDelta {
/// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks. /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
/// Panics when the duration is out of bounds. /// Panics when the duration is out of bounds.
#[inline] #[inline]
#[must_use]
pub fn days(days: i64) -> TimeDelta { pub fn days(days: i64) -> TimeDelta {
let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds"); let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds");
TimeDelta::seconds(secs) TimeDelta::seconds(secs)
@ -92,6 +94,7 @@ impl TimeDelta {
/// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
/// Panics when the duration is out of bounds. /// Panics when the duration is out of bounds.
#[inline] #[inline]
#[must_use]
pub fn hours(hours: i64) -> TimeDelta { pub fn hours(hours: i64) -> TimeDelta {
let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds"); let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds");
TimeDelta::seconds(secs) TimeDelta::seconds(secs)
@ -101,6 +104,7 @@ impl TimeDelta {
/// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
/// Panics when the duration is out of bounds. /// Panics when the duration is out of bounds.
#[inline] #[inline]
#[must_use]
pub fn minutes(minutes: i64) -> TimeDelta { pub fn minutes(minutes: i64) -> TimeDelta {
let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds"); let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds");
TimeDelta::seconds(secs) TimeDelta::seconds(secs)
@ -110,6 +114,7 @@ impl TimeDelta {
/// Panics when the duration is more than `i64::MAX` seconds /// Panics when the duration is more than `i64::MAX` seconds
/// or less than `i64::MIN` seconds. /// or less than `i64::MIN` seconds.
#[inline] #[inline]
#[must_use]
pub fn seconds(seconds: i64) -> TimeDelta { pub fn seconds(seconds: i64) -> TimeDelta {
let d = TimeDelta { secs: seconds, nanos: 0 }; let d = TimeDelta { secs: seconds, nanos: 0 };
if d < MIN || d > MAX { if d < MIN || d > MAX {
@ -211,6 +216,7 @@ impl TimeDelta {
} }
/// Add two durations, returning `None` if overflow occurred. /// Add two durations, returning `None` if overflow occurred.
#[must_use]
pub fn checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta> { pub fn checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
let mut secs = try_opt!(self.secs.checked_add(rhs.secs)); let mut secs = try_opt!(self.secs.checked_add(rhs.secs));
let mut nanos = self.nanos + rhs.nanos; let mut nanos = self.nanos + rhs.nanos;
@ -229,6 +235,7 @@ impl TimeDelta {
} }
/// Subtract two durations, returning `None` if overflow occurred. /// Subtract two durations, returning `None` if overflow occurred.
#[must_use]
pub fn checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta> { pub fn checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
let mut secs = try_opt!(self.secs.checked_sub(rhs.secs)); let mut secs = try_opt!(self.secs.checked_sub(rhs.secs));
let mut nanos = self.nanos - rhs.nanos; let mut nanos = self.nanos - rhs.nanos;

View File

@ -10,6 +10,26 @@ use crate::OutOfRange;
/// The order of the days of week depends on the context. /// The order of the days of week depends on the context.
/// (This is why this type does *not* implement `PartialOrd` or `Ord` traits.) /// (This is why this type does *not* implement `PartialOrd` or `Ord` traits.)
/// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result. /// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result.
///
/// # Example
/// ```
/// use chrono::Weekday;
/// use std::convert::TryFrom;
///
/// let monday = "Monday".parse::<Weekday>().unwrap();
/// assert_eq!(monday, Weekday::Mon);
///
/// let sunday = Weekday::try_from(6).unwrap();
/// assert_eq!(sunday, Weekday::Sun);
///
/// assert_eq!(sunday.num_days_from_monday(), 6); // starts counting with Monday = 0
/// assert_eq!(sunday.number_from_monday(), 7); // starts counting with Monday = 1
/// assert_eq!(sunday.num_days_from_sunday(), 0); // starts counting with Sunday = 0
/// assert_eq!(sunday.number_from_sunday(), 1); // starts counting with Sunday = 1
///
/// assert_eq!(sunday.succ(), monday);
/// assert_eq!(sunday.pred(), Weekday::Sat);
/// ```
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))] #[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
@ -37,6 +57,7 @@ impl Weekday {
/// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
/// `w.succ()`: | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` | `Mon` /// `w.succ()`: | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` | `Mon`
#[inline] #[inline]
#[must_use]
pub const fn succ(&self) -> Weekday { pub const fn succ(&self) -> Weekday {
match *self { match *self {
Weekday::Mon => Weekday::Tue, Weekday::Mon => Weekday::Tue,
@ -55,6 +76,7 @@ impl Weekday {
/// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | -----
/// `w.pred()`: | `Sun` | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` /// `w.pred()`: | `Sun` | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat`
#[inline] #[inline]
#[must_use]
pub const fn pred(&self) -> Weekday { pub const fn pred(&self) -> Weekday {
match *self { match *self {
Weekday::Mon => Weekday::Sun, Weekday::Mon => Weekday::Sun,

View File

@ -1,7 +1,11 @@
#[cfg(unix)]
use chrono::offset::TimeZone; use chrono::offset::TimeZone;
#[cfg(unix)]
use chrono::Local; use chrono::Local;
#[cfg(unix)]
use chrono::{Datelike, NaiveDate, NaiveDateTime, Timelike}; use chrono::{Datelike, NaiveDate, NaiveDateTime, Timelike};
#[cfg(unix)]
use std::{path, process}; use std::{path, process};
#[cfg(unix)] #[cfg(unix)]
@ -51,7 +55,10 @@ fn verify_against_date_command_local(path: &'static str, dt: NaiveDateTime) {
#[test] #[test]
#[cfg(unix)] #[cfg(unix)]
fn try_verify_against_date_command() { fn try_verify_against_date_command() {
#[cfg(not(target_os = "aix"))]
let date_path = "/usr/bin/date"; let date_path = "/usr/bin/date";
#[cfg(target_os = "aix")]
let date_path = "/opt/freeware/bin/date";
if !path::Path::new(date_path).exists() { if !path::Path::new(date_path).exists() {
// date command not found, skipping // date command not found, skipping