diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1b0af82aaf..173883b433 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -29,10 +29,10 @@ jobs: cargo clippy --target=x86_64-pc-windows-msvc --all-targets --color=always \ -- -D warnings - run: | - cargo clippy --manifest-path fuzz/Cargo.toml --color=always \ + cargo clippy --manifest-path fuzz/Cargo.toml --all-targets --color=always \ -- -D warnings - run: | - cargo clippy --manifest-path bench/Cargo.toml --color=always \ + cargo clippy --manifest-path bench/Cargo.toml --all-targets --color=always \ -- -D warnings env: RUSTFLAGS: "-Dwarnings" diff --git a/Cargo.toml b/Cargo.toml index 09c4b1f4ee..03cd467060 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ js-sys = { version = "0.3", optional = true } # contains FFI bindings for windows-targets = { version = "0.52", optional = true } [target.'cfg(windows)'.dev-dependencies] -windows-bindgen = { version = "0.54" } # The MSRV of its windows-metatada 0.54 dependency is 1.70 +windows-bindgen = { version = "0.55" } # The MSRV of its windows-metatada dependency is 1.70 [target.'cfg(unix)'.dependencies] iana-time-zone = { version = "0.1.45", optional = true, features = ["fallback"] } diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index d59a4c6204..6d98c37030 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -3,7 +3,7 @@ //! ISO 8601 date and time with time zone. -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(all(feature = "alloc", not(feature = "std"), not(test)))] use alloc::string::String; use core::borrow::Borrow; use core::cmp::Ordering; @@ -46,7 +46,7 @@ mod tests; /// There are some constructors implemented here (the `from_*` methods), but /// the general-purpose constructors are all via the methods on the /// [`TimeZone`](./offset/trait.TimeZone.html) implementations. -#[derive(Clone)] +#[derive(Copy, Clone)] #[cfg_attr( any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"), derive(Archive, Deserialize, Serialize), @@ -1260,10 +1260,6 @@ impl Timelike for DateTime { } } -// we need them as automatic impls cannot handle associated types -impl Copy for DateTime where ::Offset: Copy {} -unsafe impl Send for DateTime where ::Offset: Send {} - impl PartialEq> for DateTime { fn eq(&self, other: &DateTime) -> bool { self.datetime == other.datetime diff --git a/src/format/formatting.rs b/src/format/formatting.rs index de6e0205ae..54fda69ee5 100644 --- a/src/format/formatting.rs +++ b/src/format/formatting.rs @@ -3,7 +3,7 @@ //! Date and time formatting routines. -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(all(feature = "alloc", not(feature = "std"), not(test)))] use alloc::string::{String, ToString}; #[cfg(feature = "alloc")] use core::borrow::Borrow; @@ -20,8 +20,6 @@ use crate::{NaiveDate, NaiveTime, Weekday}; #[cfg(feature = "alloc")] use super::locales; -#[cfg(all(feature = "unstable-locales", feature = "alloc"))] -use super::Locale; #[cfg(any(feature = "alloc", feature = "serde", feature = "rustc-serialize"))] use super::{Colons, OffsetFormat, OffsetPrecision, Pad}; #[cfg(feature = "alloc")] diff --git a/src/format/mod.rs b/src/format/mod.rs index a5e0ae5b41..d145356229 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -30,7 +30,7 @@ //! # Ok::<(), chrono::ParseError>(()) //! ``` -#[cfg(all(not(feature = "std"), feature = "alloc"))] +#[cfg(all(feature = "alloc", not(feature = "std"), not(test)))] use alloc::boxed::Box; use core::fmt; use core::str::FromStr; diff --git a/src/format/strftime.rs b/src/format/strftime.rs index 32c483dbc0..d928c7bac6 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -165,7 +165,7 @@ use super::{locales, Locale}; use super::{Fixed, InternalInternal, Item, Numeric, Pad}; #[cfg(any(feature = "alloc", feature = "std"))] use super::{ParseError, BAD_FORMAT}; -#[cfg(feature = "alloc")] +#[cfg(all(feature = "alloc", not(feature = "std"), not(test)))] use alloc::vec::Vec; /// Parsing iterator for `strftime`-like format strings. diff --git a/src/naive/date/tests.rs b/src/naive/date/tests.rs index 734e393393..997345407b 100644 --- a/src/naive/date/tests.rs +++ b/src/naive/date/tests.rs @@ -442,98 +442,102 @@ fn test_date_pred() { } #[test] -fn test_date_add() { - fn check((y1, m1, d1): (i32, u32, u32), rhs: TimeDelta, ymd: Option<(i32, u32, u32)>) { - let lhs = NaiveDate::from_ymd(y1, m1, d1).unwrap(); - let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd(y, m, d).unwrap()); - assert_eq!(lhs.checked_add_signed(rhs), sum); - assert_eq!(lhs.checked_sub_signed(-rhs), sum); +fn test_date_checked_add_signed() { + fn check(lhs: Option, delta: TimeDelta, rhs: Option) { + assert_eq!(lhs.unwrap().checked_add_signed(delta), rhs); + assert_eq!(lhs.unwrap().checked_sub_signed(-delta), rhs); } + let ymd = |y, m, d| NaiveDate::from_ymd(y, m, d).ok(); - check((2014, 1, 1), TimeDelta::zero(), Some((2014, 1, 1))); - check((2014, 1, 1), TimeDelta::seconds(86399).unwrap(), Some((2014, 1, 1))); + check(ymd(2014, 1, 1), TimeDelta::zero(), ymd(2014, 1, 1)); + check(ymd(2014, 1, 1), TimeDelta::seconds(86399).unwrap(), ymd(2014, 1, 1)); // always round towards zero - check((2014, 1, 1), TimeDelta::seconds(-86399).unwrap(), Some((2014, 1, 1))); - check((2014, 1, 1), TimeDelta::days(1).unwrap(), Some((2014, 1, 2))); - check((2014, 1, 1), TimeDelta::days(-1).unwrap(), Some((2013, 12, 31))); - check((2014, 1, 1), TimeDelta::days(364).unwrap(), Some((2014, 12, 31))); - check((2014, 1, 1), TimeDelta::days(365 * 4 + 1).unwrap(), Some((2018, 1, 1))); - check((2014, 1, 1), TimeDelta::days(365 * 400 + 97).unwrap(), Some((2414, 1, 1))); + check(ymd(2014, 1, 1), TimeDelta::seconds(-86399).unwrap(), ymd(2014, 1, 1)); + check(ymd(2014, 1, 1), TimeDelta::days(1).unwrap(), ymd(2014, 1, 2)); + check(ymd(2014, 1, 1), TimeDelta::days(-1).unwrap(), ymd(2013, 12, 31)); + check(ymd(2014, 1, 1), TimeDelta::days(364).unwrap(), ymd(2014, 12, 31)); + check(ymd(2014, 1, 1), TimeDelta::days(365 * 4 + 1).unwrap(), ymd(2018, 1, 1)); + check(ymd(2014, 1, 1), TimeDelta::days(365 * 400 + 97).unwrap(), ymd(2414, 1, 1)); - check((-7, 1, 1), TimeDelta::days(365 * 12 + 3).unwrap(), Some((5, 1, 1))); + check(ymd(-7, 1, 1), TimeDelta::days(365 * 12 + 3).unwrap(), ymd(5, 1, 1)); // overflow check check( - (0, 1, 1), + ymd(0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64).unwrap(), - Some((MAX_YEAR, 12, 31)), + ymd(MAX_YEAR, 12, 31), ); - check((0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64 + 1).unwrap(), None); - check((0, 1, 1), TimeDelta::max_value(), None); - check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64).unwrap(), Some((MIN_YEAR, 1, 1))); - check((0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64 - 1).unwrap(), None); - check((0, 1, 1), TimeDelta::min_value(), None); + check(ymd(0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64 + 1).unwrap(), None); + check(ymd(0, 1, 1), TimeDelta::max_value(), None); + check(ymd(0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64).unwrap(), ymd(MIN_YEAR, 1, 1)); + check(ymd(0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64 - 1).unwrap(), None); + check(ymd(0, 1, 1), TimeDelta::min_value(), None); } #[test] -fn test_date_sub() { - fn check((y1, m1, d1): (i32, u32, u32), (y2, m2, d2): (i32, u32, u32), diff: TimeDelta) { - let lhs = NaiveDate::from_ymd(y1, m1, d1).unwrap(); - let rhs = NaiveDate::from_ymd(y2, m2, d2).unwrap(); - assert_eq!(lhs.signed_duration_since(rhs), diff); - assert_eq!(rhs.signed_duration_since(lhs), -diff); +fn test_date_signed_duration_since() { + fn check(lhs: Option, rhs: Option, delta: TimeDelta) { + assert_eq!(lhs.unwrap().signed_duration_since(rhs.unwrap()), delta); + assert_eq!(rhs.unwrap().signed_duration_since(lhs.unwrap()), -delta); } + let ymd = |y, m, d| NaiveDate::from_ymd(y, m, d).ok(); - check((2014, 1, 1), (2014, 1, 1), TimeDelta::zero()); - check((2014, 1, 2), (2014, 1, 1), TimeDelta::days(1).unwrap()); - check((2014, 12, 31), (2014, 1, 1), TimeDelta::days(364).unwrap()); - check((2015, 1, 3), (2014, 1, 1), TimeDelta::days(365 + 2).unwrap()); - check((2018, 1, 1), (2014, 1, 1), TimeDelta::days(365 * 4 + 1).unwrap()); - check((2414, 1, 1), (2014, 1, 1), TimeDelta::days(365 * 400 + 97).unwrap()); + check(ymd(2014, 1, 1), ymd(2014, 1, 1), TimeDelta::zero()); + check(ymd(2014, 1, 2), ymd(2014, 1, 1), TimeDelta::days(1).unwrap()); + check(ymd(2014, 12, 31), ymd(2014, 1, 1), TimeDelta::days(364).unwrap()); + check(ymd(2015, 1, 3), ymd(2014, 1, 1), TimeDelta::days(365 + 2).unwrap()); + check(ymd(2018, 1, 1), ymd(2014, 1, 1), TimeDelta::days(365 * 4 + 1).unwrap()); + check(ymd(2414, 1, 1), ymd(2014, 1, 1), TimeDelta::days(365 * 400 + 97).unwrap()); - check((MAX_YEAR, 12, 31), (0, 1, 1), TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64).unwrap()); - check((MIN_YEAR, 1, 1), (0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64).unwrap()); + check( + ymd(MAX_YEAR, 12, 31), + ymd(0, 1, 1), + TimeDelta::days(MAX_DAYS_FROM_YEAR_0 as i64).unwrap(), + ); + check(ymd(MIN_YEAR, 1, 1), ymd(0, 1, 1), TimeDelta::days(MIN_DAYS_FROM_YEAR_0 as i64).unwrap()); } #[test] fn test_date_add_days() { - fn check((y1, m1, d1): (i32, u32, u32), rhs: Days, ymd: Option<(i32, u32, u32)>) { - let lhs = NaiveDate::from_ymd(y1, m1, d1).unwrap(); - let sum = ymd.map(|(y, m, d)| NaiveDate::from_ymd(y, m, d).unwrap()); - assert_eq!(lhs.checked_add_days(rhs), sum); + fn check(lhs: Option, days: Days, rhs: Option) { + assert_eq!(lhs.unwrap().checked_add_days(days), rhs); } + let ymd = |y, m, d| NaiveDate::from_ymd(y, m, d).ok(); - check((2014, 1, 1), Days::new(0), Some((2014, 1, 1))); + check(ymd(2014, 1, 1), Days::new(0), ymd(2014, 1, 1)); // always round towards zero - check((2014, 1, 1), Days::new(1), Some((2014, 1, 2))); - check((2014, 1, 1), Days::new(364), Some((2014, 12, 31))); - check((2014, 1, 1), Days::new(365 * 4 + 1), Some((2018, 1, 1))); - check((2014, 1, 1), Days::new(365 * 400 + 97), Some((2414, 1, 1))); + check(ymd(2014, 1, 1), Days::new(1), ymd(2014, 1, 2)); + check(ymd(2014, 1, 1), Days::new(364), ymd(2014, 12, 31)); + check(ymd(2014, 1, 1), Days::new(365 * 4 + 1), ymd(2018, 1, 1)); + check(ymd(2014, 1, 1), Days::new(365 * 400 + 97), ymd(2414, 1, 1)); - check((-7, 1, 1), Days::new(365 * 12 + 3), Some((5, 1, 1))); + check(ymd(-7, 1, 1), Days::new(365 * 12 + 3), ymd(5, 1, 1)); // overflow check - check((0, 1, 1), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()), Some((MAX_YEAR, 12, 31))); - check((0, 1, 1), Days::new(u64::try_from(MAX_DAYS_FROM_YEAR_0).unwrap() + 1), None); + check(ymd(0, 1, 1), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()), ymd(MAX_YEAR, 12, 31)); + check(ymd(0, 1, 1), Days::new(u64::try_from(MAX_DAYS_FROM_YEAR_0).unwrap() + 1), None); } #[test] fn test_date_sub_days() { - fn check((y1, m1, d1): (i32, u32, u32), (y2, m2, d2): (i32, u32, u32), diff: Days) { - let lhs = NaiveDate::from_ymd(y1, m1, d1).unwrap(); - let rhs = NaiveDate::from_ymd(y2, m2, d2).unwrap(); - assert_eq!(lhs - diff, rhs); + fn check(lhs: Option, days: Days, rhs: Option) { + assert_eq!(lhs.unwrap().checked_sub_days(days), rhs); } + let ymd = |y, m, d| NaiveDate::from_ymd(y, m, d).ok(); - check((2014, 1, 1), (2014, 1, 1), Days::new(0)); - check((2014, 1, 2), (2014, 1, 1), Days::new(1)); - check((2014, 12, 31), (2014, 1, 1), Days::new(364)); - check((2015, 1, 3), (2014, 1, 1), Days::new(365 + 2)); - check((2018, 1, 1), (2014, 1, 1), Days::new(365 * 4 + 1)); - check((2414, 1, 1), (2014, 1, 1), Days::new(365 * 400 + 97)); + check(ymd(2014, 1, 1), Days::new(0), ymd(2014, 1, 1)); + check(ymd(2014, 1, 2), Days::new(1), ymd(2014, 1, 1)); + check(ymd(2014, 12, 31), Days::new(364), ymd(2014, 1, 1)); + check(ymd(2015, 1, 3), Days::new(365 + 2), ymd(2014, 1, 1)); + check(ymd(2018, 1, 1), Days::new(365 * 4 + 1), ymd(2014, 1, 1)); + check(ymd(2414, 1, 1), Days::new(365 * 400 + 97), ymd(2014, 1, 1)); - check((MAX_YEAR, 12, 31), (0, 1, 1), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap())); - check((0, 1, 1), (MIN_YEAR, 1, 1), Days::new((-MIN_DAYS_FROM_YEAR_0).try_into().unwrap())); + check(ymd(MAX_YEAR, 12, 31), Days::new(MAX_DAYS_FROM_YEAR_0.try_into().unwrap()), ymd(0, 1, 1)); + check( + ymd(0, 1, 1), + Days::new((-MIN_DAYS_FROM_YEAR_0).try_into().unwrap()), + ymd(MIN_YEAR, 1, 1), + ); } #[test] diff --git a/src/offset/local/win_bindings.rs b/src/offset/local/win_bindings.rs index 39060adadd..ca2def1e65 100644 --- a/src/offset/local/win_bindings.rs +++ b/src/offset/local/win_bindings.rs @@ -1,10 +1,8 @@ -// Bindings generated by `windows-bindgen` 0.54.0 - #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)] -::windows_targets::link!("kernel32.dll" "system" fn GetTimeZoneInformationForYear(wyear : u16, pdtzi : *const DYNAMIC_TIME_ZONE_INFORMATION, ptzi : *mut TIME_ZONE_INFORMATION) -> BOOL); -::windows_targets::link!("kernel32.dll" "system" fn SystemTimeToFileTime(lpsystemtime : *const SYSTEMTIME, lpfiletime : *mut FILETIME) -> BOOL); -::windows_targets::link!("kernel32.dll" "system" fn SystemTimeToTzSpecificLocalTime(lptimezoneinformation : *const TIME_ZONE_INFORMATION, lpuniversaltime : *const SYSTEMTIME, lplocaltime : *mut SYSTEMTIME) -> BOOL); -::windows_targets::link!("kernel32.dll" "system" fn TzSpecificLocalTimeToSystemTime(lptimezoneinformation : *const TIME_ZONE_INFORMATION, lplocaltime : *const SYSTEMTIME, lpuniversaltime : *mut SYSTEMTIME) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetTimeZoneInformationForYear(wyear : u16, pdtzi : *const DYNAMIC_TIME_ZONE_INFORMATION, ptzi : *mut TIME_ZONE_INFORMATION) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SystemTimeToFileTime(lpsystemtime : *const SYSTEMTIME, lpfiletime : *mut FILETIME) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn SystemTimeToTzSpecificLocalTime(lptimezoneinformation : *const TIME_ZONE_INFORMATION, lpuniversaltime : *const SYSTEMTIME, lplocaltime : *mut SYSTEMTIME) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn TzSpecificLocalTimeToSystemTime(lptimezoneinformation : *const TIME_ZONE_INFORMATION, lplocaltime : *const SYSTEMTIME, lpuniversaltime : *mut SYSTEMTIME) -> BOOL); pub type BOOL = i32; pub type BOOLEAN = u8; #[repr(C)] @@ -19,8 +17,8 @@ pub struct DYNAMIC_TIME_ZONE_INFORMATION { pub TimeZoneKeyName: [u16; 128], pub DynamicDaylightTimeDisabled: BOOLEAN, } -impl ::core::marker::Copy for DYNAMIC_TIME_ZONE_INFORMATION {} -impl ::core::clone::Clone for DYNAMIC_TIME_ZONE_INFORMATION { +impl Copy for DYNAMIC_TIME_ZONE_INFORMATION {} +impl Clone for DYNAMIC_TIME_ZONE_INFORMATION { fn clone(&self) -> Self { *self } @@ -30,8 +28,8 @@ pub struct FILETIME { pub dwLowDateTime: u32, pub dwHighDateTime: u32, } -impl ::core::marker::Copy for FILETIME {} -impl ::core::clone::Clone for FILETIME { +impl Copy for FILETIME {} +impl Clone for FILETIME { fn clone(&self) -> Self { *self } @@ -47,8 +45,8 @@ pub struct SYSTEMTIME { pub wSecond: u16, pub wMilliseconds: u16, } -impl ::core::marker::Copy for SYSTEMTIME {} -impl ::core::clone::Clone for SYSTEMTIME { +impl Copy for SYSTEMTIME {} +impl Clone for SYSTEMTIME { fn clone(&self) -> Self { *self } @@ -63,8 +61,8 @@ pub struct TIME_ZONE_INFORMATION { pub DaylightDate: SYSTEMTIME, pub DaylightBias: i32, } -impl ::core::marker::Copy for TIME_ZONE_INFORMATION {} -impl ::core::clone::Clone for TIME_ZONE_INFORMATION { +impl Copy for TIME_ZONE_INFORMATION {} +impl Clone for TIME_ZONE_INFORMATION { fn clone(&self) -> Self { *self } diff --git a/src/offset/local/win_bindings.txt b/src/offset/local/win_bindings.txt index 7fb3e2fa1c..fc00509cfb 100644 --- a/src/offset/local/win_bindings.txt +++ b/src/offset/local/win_bindings.txt @@ -1,5 +1,5 @@ --out src/offset/local/win_bindings.rs ---config flatten sys +--config flatten sys no-bindgen-comment --filter Windows.Win32.System.Time.GetTimeZoneInformationForYear Windows.Win32.System.Time.SystemTimeToFileTime diff --git a/src/offset/local/windows.rs b/src/offset/local/windows.rs index 1319ec6fea..2370297cc1 100644 --- a/src/offset/local/windows.rs +++ b/src/offset/local/windows.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::cmp::Ordering; -use std::convert::TryFrom; use std::mem::MaybeUninit; use std::ptr; @@ -141,18 +140,38 @@ impl TzInfo { } tz_info.assume_init() }; + let std_offset = (tz_info.Bias) + .checked_add(tz_info.StandardBias) + .and_then(|o| o.checked_mul(60)) + .and_then(|o| FixedOffset::west(o).ok())?; + let dst_offset = (tz_info.Bias) + .checked_add(tz_info.DaylightBias) + .and_then(|o| o.checked_mul(60)) + .and_then(|o| FixedOffset::west(o).ok())?; Some(TzInfo { - std_offset: FixedOffset::west((tz_info.Bias + tz_info.StandardBias) * 60).ok()?, - dst_offset: FixedOffset::west((tz_info.Bias + tz_info.DaylightBias) * 60).ok()?, - std_transition: system_time_from_naive_date_time(tz_info.StandardDate, year), - dst_transition: system_time_from_naive_date_time(tz_info.DaylightDate, year), + std_offset, + dst_offset, + std_transition: naive_date_time_from_system_time(tz_info.StandardDate, year).ok()?, + dst_transition: naive_date_time_from_system_time(tz_info.DaylightDate, year).ok()?, }) } } -fn system_time_from_naive_date_time(st: SYSTEMTIME, year: i32) -> Option { +/// Resolve a `SYSTEMTIME` object to an `Option`. +/// +/// A `SYSTEMTIME` within a `TIME_ZONE_INFORMATION` struct can be zero to indicate there is no +/// transition. +/// If it has year, month and day values it is a concrete date. +/// If the year is missing the `SYSTEMTIME` is a rule, which this method resolves for the provided +/// year. A rule has a month, weekday, and nth weekday of the month as components. +/// +/// Returns `Err` if any of the values is invalid, which should never happen. +fn naive_date_time_from_system_time( + st: SYSTEMTIME, + year: i32, +) -> Result, ()> { if st.wYear == 0 && st.wMonth == 0 { - return None; // No DST transitions for this year in this timezone. + return Ok(None); } let time = NaiveTime::from_hms_milli( st.wHour as u32, @@ -160,25 +179,35 @@ fn system_time_from_naive_date_time(st: SYSTEMTIME, year: i32) -> Option Weekday::Sun, + 1 => Weekday::Mon, + 2 => Weekday::Tue, + 3 => Weekday::Wed, + 4 => Weekday::Thu, + 5 => Weekday::Fri, + 6 => Weekday::Sat, + _ => return Err(()), + }; + let nth_day = match st.wDay { + 1..=5 => st.wDay as u8, + _ => return Err(()), }; - Some(date.and_time(time)) + let date = NaiveDate::from_weekday_of_month(year, st.wMonth as u32, weekday, nth_day) + .or_else(|| NaiveDate::from_weekday_of_month(year, st.wMonth as u32, weekday, 4)) + .ok_or(())?; // `st.wMonth` must be invalid + Ok(Some(date.and_time(time))) } #[cfg(test)] diff --git a/src/round.rs b/src/round.rs index f493ea4922..06fbcca849 100644 --- a/src/round.rs +++ b/src/round.rs @@ -6,7 +6,6 @@ use crate::{DateTime, NaiveDateTime, TimeDelta, TimeZone, Timelike}; use core::cmp::Ordering; use core::fmt; -use core::marker::Sized; use core::ops::{Add, Sub}; /// Extension trait for subsecond rounding or truncation to a maximum number