From 96b5ba391b7a04b4c11c7043adbb9287d6fd4d68 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Tue, 7 Feb 2017 04:26:29 +0900 Subject: [PATCH] Fixed a panic when the Local offset receives a leap second. Fixes #123. --- src/offset/local.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/offset/local.rs b/src/offset/local.rs index c470d9a..8dd8b2e 100644 --- a/src/offset/local.rs +++ b/src/offset/local.rs @@ -49,7 +49,7 @@ fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> oldtime::Timespec { // the number 1 is arbitrary but should be non-zero to trigger `mktime`. let tm_utcoff = if local {1} else {0}; - let tm = oldtime::Tm { + let mut tm = oldtime::Tm { tm_sec: d.second() as i32, tm_min: d.minute() as i32, tm_hour: d.hour() as i32, @@ -62,6 +62,13 @@ fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> oldtime::Timespec { tm_utcoff: tm_utcoff, tm_nsec: d.nanosecond() as i32, }; + + // adjustment for the leap second + if tm.tm_nsec >= 1_000_000_000 { + tm.tm_sec += 1; + tm.tm_nsec -= 1_000_000_000; + } + tm.to_timespec() } @@ -147,5 +154,19 @@ mod tests { fn test_local_date_sanity_check() { // issue #27 assert_eq!(Local.ymd(2999, 12, 28).day(), 28); } + + #[test] + fn test_leap_second() { // issue #123 + let today = Local::today(); + let dt = today.and_hms_milli(1, 2, 59, 1000); + let timestr = dt.time().to_string(); + // the OS API may or may not support the leap second, + // but there are only two sensible options. + assert!(timestr == "01:02:60" || timestr == "01:03:00", + "unexpected timestr {:?}", timestr); + + // this case, while unsupported by most APIs, should *not* panic. + let _ = today.and_hms_milli_opt(1, 2, 3, 1000); + } }