Deny leap second if secs != 59 in from_num_seconds_from_midnight_opt

This commit is contained in:
Paul Dicker 2023-09-12 08:36:52 +02:00 committed by Paul Dicker
parent 61b7ffbb7a
commit 6665804676
4 changed files with 34 additions and 15 deletions

View File

@ -596,12 +596,18 @@ impl DateTime<Utc> {
/// 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
///
/// ```

View File

@ -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]

View File

@ -425,8 +425,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 to exceed 1,000,000,000 in order to represent a
/// [leap second](#leap-second-handling), but only when `secs % 60 == 59`.
///
/// # Panics
///
@ -440,8 +440,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 to exceed 1,000,000,000 in order to represent a
/// [leap second](#leap-second-handling), but only when `secs % 60 == 59`.
///
/// # Errors
///
@ -463,7 +463,7 @@ impl NaiveTime {
#[inline]
#[must_use]
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 || (nano >= 1_000_000_000 && secs % 60 != 59) {
return None;
}
Some(NaiveTime { secs, frac: nano })

View File

@ -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`.
///