diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 78c3974ccb..3dfe8a1e30 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -579,12 +579,18 @@ impl DateTime { /// This is guaranteed to round-trip with regard to [`timestamp`](DateTime::timestamp) and /// [`timestamp_subsec_nanos`](DateTime::timestamp_subsec_nanos). /// - /// Returns `None` on out-of-range number of seconds and/or - /// invalid nanosecond, otherwise returns `Some(DateTime {...})`. - /// /// If you need to create a `DateTime` with a [`TimeZone`] different from [`Utc`], use /// [`TimeZone::timestamp_opt`] or [`DateTime::with_timezone`]. /// + /// The nanosecond part can exceed 1,000,000,000 in order to represent a + /// [leap second](NaiveTime#leap-second-handling), but only when `secs % 60 == 59`. + /// (The true "UNIX timestamp" cannot represent a leap second unambiguously.) + /// + /// # Errors + /// + /// Returns `None` on out-of-range number of seconds and/or + /// invalid nanosecond, otherwise returns `Some(DateTime {...})`. + /// /// # Example /// /// ``` diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index 387f03207d..32367e0372 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -110,9 +110,9 @@ impl NaiveDateTime { /// For a non-naive version of this function see /// [`TimeZone::timestamp`](../offset/trait.TimeZone.html#method.timestamp). /// - /// The nanosecond part can exceed 1,000,000,000 in order to represent the - /// [leap second](./struct.NaiveTime.html#leap-second-handling). (The true "UNIX - /// timestamp" cannot represent a leap second unambiguously.) + /// The nanosecond part can exceed 1,000,000,000 in order to represent a + /// [leap second](NaiveTime#leap-second-handling), but only when `secs % 60 == 59`. + /// (The true "UNIX timestamp" cannot represent a leap second unambiguously.) /// /// # Panics /// @@ -196,8 +196,8 @@ impl NaiveDateTime { /// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp") /// and the number of nanoseconds since the last whole non-leap second. /// - /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// The nanosecond part can exceed 1,000,000,000 in order to represent a + /// [leap second](NaiveTime#leap-second-handling), but only when `secs % 60 == 59`. /// (The true "UNIX timestamp" cannot represent a leap second unambiguously.) /// /// # Errors @@ -216,8 +216,9 @@ impl NaiveDateTime { /// /// assert!(from_timestamp_opt(0, 0).is_some()); /// assert!(from_timestamp_opt(0, 999_999_999).is_some()); - /// assert!(from_timestamp_opt(0, 1_500_000_000).is_some()); // leap second - /// assert!(from_timestamp_opt(0, 2_000_000_000).is_none()); + /// assert!(from_timestamp_opt(0, 1_500_000_000).is_none()); // invalid leap second + /// assert!(from_timestamp_opt(59, 1_500_000_000).is_some()); // leap second + /// assert!(from_timestamp_opt(59, 2_000_000_000).is_none()); /// assert!(from_timestamp_opt(i64::MAX, 0).is_none()); /// ``` #[inline] diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index 4e854b2418..6bc73135b7 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -420,8 +420,8 @@ impl NaiveTime { /// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond. /// - /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](#leap-second-handling). + /// The nanosecond part is allowed exceed 1,000,000,000 in order to represent a + /// [leap second](#leap-second-handling), but only when `secs % 60 == 59`. /// /// # Panics /// @@ -435,8 +435,8 @@ impl NaiveTime { /// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond. /// - /// The nanosecond part can exceed 1,000,000,000 - /// in order to represent the [leap second](#leap-second-handling). + /// The nanosecond part is allowed exceed 1,000,000,000 in order to represent a + /// [leap second](#leap-second-handling), but only when `secs % 60 == 59`. /// /// # Errors /// @@ -458,8 +458,10 @@ impl NaiveTime { #[inline] #[must_use] pub const fn from_num_seconds_from_midnight_opt(secs: u32, nano: u32) -> Option { - if secs >= 86_400 || nano >= 2_000_000_000 { - return None; + if secs >= 86_400 || nano >= 1_000_000_000 { + if !(secs < 86_400 && secs % 60 == 59 && nano < 2_000_000_000) { + return None; + } } Some(NaiveTime { secs, frac: nano }) } diff --git a/src/offset/mod.rs b/src/offset/mod.rs index 419550e292..7f5857b234 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -347,6 +347,12 @@ pub trait TimeZone: Sized + Clone { /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp") /// and the number of nanoseconds since the last whole non-leap second. /// + /// The nanosecond part can exceed 1,000,000,000 in order to represent a + /// [leap second](NaiveTime#leap-second-handling), but only when `secs % 60 == 59`. + /// (The true "UNIX timestamp" cannot represent a leap second unambiguously.) + /// + /// # Panics + /// /// Panics on the out-of-range number of seconds and/or invalid nanosecond, /// for a non-panicking version see [`timestamp_opt`](#method.timestamp_opt). #[deprecated(since = "0.4.23", note = "use `timestamp_opt()` instead")] @@ -358,6 +364,12 @@ pub trait TimeZone: Sized + Clone { /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp") /// and the number of nanoseconds since the last whole non-leap second. /// + /// The nanosecond part can exceed 1,000,000,000 in order to represent a + /// [leap second](NaiveTime#leap-second-handling), but only when `secs % 60 == 59`. + /// (The true "UNIX timestamp" cannot represent a leap second unambiguously.) + /// + /// # Errors + /// /// Returns `LocalResult::None` on out-of-range number of seconds and/or /// invalid nanosecond, otherwise always returns `LocalResult::Single`. ///