From fd0c9483acd59722baf7e4481937f7aaec0e0535 Mon Sep 17 00:00:00 2001 From: Alberto Donato Date: Tue, 15 Aug 2023 17:19:02 +0300 Subject: [PATCH] output six decimal digits for timestamp microseconds (#47) output six decimal digits for timestamp nanonseconds --- fuzz/fuzz_targets/parse_float.rs | 2 +- fuzz/fuzz_targets/parse_int.rs | 2 +- src/datetime.rs | 4 +- src/time.rs | 2 +- tests/main.rs | 32 ++++++++-------- tests/values_ok.txt | 66 ++++++++++++++++---------------- 6 files changed, 54 insertions(+), 54 deletions(-) diff --git a/fuzz/fuzz_targets/parse_float.rs b/fuzz/fuzz_targets/parse_float.rs index 843cd02..11d3d2f 100644 --- a/fuzz/fuzz_targets/parse_float.rs +++ b/fuzz/fuzz_targets/parse_float.rs @@ -6,7 +6,7 @@ fn check_float_matches(data: &str) { match float_parse_str(data) { IntFloat::Int(i) => assert_eq!(data.parse::().unwrap(), i), IntFloat::Float(f) => assert_eq!(data.parse::().unwrap(), f), - IntFloat::Err => assert!(data.parse::().is_err()) + IntFloat::Err => assert!(data.parse::().is_err()), } } diff --git a/fuzz/fuzz_targets/parse_int.rs b/fuzz/fuzz_targets/parse_int.rs index e045b2e..c19ab54 100644 --- a/fuzz/fuzz_targets/parse_int.rs +++ b/fuzz/fuzz_targets/parse_int.rs @@ -5,7 +5,7 @@ use speedate::int_parse_str; fn check_int_matches(data: &str) { match int_parse_str(data) { Some(i) => assert_eq!(data.parse::().unwrap(), i), - None => assert!(data.parse::().is_err()) + None => assert!(data.parse::().is_err()), } } diff --git a/src/datetime.rs b/src/datetime.rs index ab46210..4646202 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -371,7 +371,7 @@ impl DateTime { /// assert_eq!(d.to_string(), "2022-06-07T16:28:40.000123"); /// /// let d = DateTime::from_timestamp_with_config(1_654_619_320_123, 123_000, &TimeConfigBuilder::new().build()).unwrap(); - /// assert_eq!(d.to_string(), "2022-06-07T16:28:40.246"); + /// assert_eq!(d.to_string(), "2022-06-07T16:28:40.246000"); /// ``` pub fn from_timestamp_with_config( timestamp: i64, @@ -429,7 +429,7 @@ impl DateTime { /// assert_eq!(d.to_string(), "2022-06-07T16:28:40.000123"); /// /// let d = DateTime::from_timestamp(1_654_619_320_123, 123_000).unwrap(); - /// assert_eq!(d.to_string(), "2022-06-07T16:28:40.246"); + /// assert_eq!(d.to_string(), "2022-06-07T16:28:40.246000"); /// ``` pub fn from_timestamp(timestamp: i64, timestamp_microsecond: u32) -> Result { Self::from_timestamp_with_config(timestamp, timestamp_microsecond, &TimeConfigBuilder::new().build()) diff --git a/src/time.rs b/src/time.rs index 3922d55..10c2f7d 100644 --- a/src/time.rs +++ b/src/time.rs @@ -45,7 +45,7 @@ impl fmt::Display for Time { crate::display_num_buf(2, 3, self.minute as u32, &mut buf); crate::display_num_buf(2, 6, self.second as u32, &mut buf); crate::display_num_buf(6, 9, self.microsecond, &mut buf); - f.write_str(std::str::from_utf8(&buf[..]).unwrap().trim_end_matches('0'))? + f.write_str(std::str::from_utf8(&buf[..]).unwrap())? } else { let mut buf: [u8; 8] = *b"00:00:00"; crate::display_num_buf(2, 0, self.hour as u32, &mut buf); diff --git a/tests/main.rs b/tests/main.rs index 1834839..50a9df9 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -424,13 +424,13 @@ fn datetime_watershed() { let dt = DateTime::from_timestamp(20_000_000_000, 0).unwrap(); assert_eq!(dt.to_string(), "2603-10-11T11:33:20"); let dt = DateTime::from_timestamp(20_000_000_001, 0).unwrap(); - assert_eq!(dt.to_string(), "1970-08-20T11:33:20.001"); + assert_eq!(dt.to_string(), "1970-08-20T11:33:20.001000"); match DateTime::from_timestamp(-20_000_000_000, 0) { Ok(dt) => panic!("unexpectedly valid, {dt}"), Err(e) => assert_eq!(e, ParseError::DateTooSmall), } let dt = DateTime::from_timestamp(-20_000_000_001, 0).unwrap(); - assert_eq!(dt.to_string(), "1969-05-14T12:26:39.999"); + assert_eq!(dt.to_string(), "1969-05-14T12:26:39.999000"); } #[test] @@ -456,10 +456,10 @@ fn datetime_with_tz_offset() { let dt_z = DateTime::parse_str("2022-01-01T12:13:14.567+00:00").unwrap(); let dt_m8 = dt_z.with_timezone_offset(Some(-8 * 3600)).unwrap(); - assert_eq!(dt_m8.to_string(), "2022-01-01T12:13:14.567-08:00"); + assert_eq!(dt_m8.to_string(), "2022-01-01T12:13:14.567000-08:00"); let dt_naive = dt_z.with_timezone_offset(None).unwrap(); - assert_eq!(dt_naive.to_string(), "2022-01-01T12:13:14.567"); + assert_eq!(dt_naive.to_string(), "2022-01-01T12:13:14.567000"); let dt_naive = DateTime::parse_str("2000-01-01T00:00:00").unwrap(); @@ -475,13 +475,13 @@ fn datetime_with_tz_offset() { #[test] fn datetime_in_timezone() { - let dt_z = DateTime::parse_str("2000-01-01T15:00:00.567Z").unwrap(); + let dt_z = DateTime::parse_str("2000-01-01T15:00:00.567000Z").unwrap(); let dt_p1 = dt_z.in_timezone(3_600).unwrap(); - assert_eq!(dt_p1.to_string(), "2000-01-01T16:00:00.567+01:00"); + assert_eq!(dt_p1.to_string(), "2000-01-01T16:00:00.567000+01:00"); let dt_m2 = dt_z.in_timezone(-7_200).unwrap(); - assert_eq!(dt_m2.to_string(), "2000-01-01T13:00:00.567-02:00"); + assert_eq!(dt_m2.to_string(), "2000-01-01T13:00:00.567000-02:00"); let dt_naive = DateTime::parse_str("2000-01-01T00:00:00").unwrap(); let error = match dt_naive.in_timezone(3_600) { @@ -573,10 +573,10 @@ fn time_with_tz_offset() { let t_z = Time::parse_str("12:13:14.567+00:00").unwrap(); let t_m8 = t_z.with_timezone_offset(Some(-8 * 3600)).unwrap(); - assert_eq!(t_m8.to_string(), "12:13:14.567-08:00"); + assert_eq!(t_m8.to_string(), "12:13:14.567000-08:00"); let t_naive = t_z.with_timezone_offset(None).unwrap(); - assert_eq!(t_naive.to_string(), "12:13:14.567"); + assert_eq!(t_naive.to_string(), "12:13:14.567000"); let t_naive = Time::parse_str("00:00:00").unwrap(); @@ -595,10 +595,10 @@ fn time_in_timezone() { let t_z = Time::parse_str("15:00:00.567Z").unwrap(); let t_p1 = t_z.in_timezone(3_600).unwrap(); - assert_eq!(t_p1.to_string(), "16:00:00.567+01:00"); + assert_eq!(t_p1.to_string(), "16:00:00.567000+01:00"); let t_m2 = t_z.in_timezone(-7_200).unwrap(); - assert_eq!(t_m2.to_string(), "13:00:00.567-02:00"); + assert_eq!(t_m2.to_string(), "13:00:00.567000-02:00"); let t_naive = Time::parse_str("10:00:00").unwrap(); let error = match t_naive.in_timezone(3_600) { @@ -619,7 +619,7 @@ param_tests! { time_min: ok => "00:00:00.000000", "00:00:00"; time_max: ok => "23:59:59.999999", "23:59:59.999999"; time_no_fraction: ok => "12:13:14", "12:13:14"; - time_fraction_small: ok => "12:13:14.123", "12:13:14.123"; + time_fraction_small: ok => "12:13:14.123", "12:13:14.123000"; time_no_sec: ok => "12:13", "12:13:00"; time_tz: ok => "12:13:14z", "12:13:14Z"; time: err => "xxx", TooShort; @@ -813,12 +813,12 @@ param_tests! { dt_tz_negative: ok => "2020-01-01T12:13:14-02:15", "2020-01-01T12:13:14-02:15"; dt_tz_negative_10: ok => "2020-01-01T12:13:14-11:30", "2020-01-01T12:13:14-11:30"; dt_tz_no_colon: ok => "2020-01-01T12:13:14+1234", "2020-01-01T12:13:14+12:34"; - dt_seconds_fraction_break: ok => "2020-01-01 12:13:14.123z", "2020-01-01T12:13:14.123Z"; - dt_seconds_fraction_comma: ok => "2020-01-01 12:13:14,123z", "2020-01-01T12:13:14.123Z"; - dt_underscore: ok => "2020-01-01_12:13:14,123z", "2020-01-01T12:13:14.123Z"; + dt_seconds_fraction_break: ok => "2020-01-01 12:13:14.123z", "2020-01-01T12:13:14.123000Z"; + dt_seconds_fraction_comma: ok => "2020-01-01 12:13:14,123z", "2020-01-01T12:13:14.123000Z"; + dt_underscore: ok => "2020-01-01_12:13:14,123z", "2020-01-01T12:13:14.123000Z"; dt_unix1: ok => "1654646400", "2022-06-08T00:00:00"; dt_unix2: ok => "1654646404", "2022-06-08T00:00:04"; - dt_unix_float: ok => "1654646404.5", "2022-06-08T00:00:04.5"; + dt_unix_float: ok => "1654646404.5", "2022-06-08T00:00:04.500000"; dt_short_date: err => "xxx", TooShort; dt_short_time: err => "2020-01-01T12:0", TooShort; dt: err => "202x-01-01", InvalidCharYear; diff --git a/tests/values_ok.txt b/tests/values_ok.txt index 6a3199a..f44ebc4 100644 --- a/tests/values_ok.txt +++ b/tests/values_ok.txt @@ -2,56 +2,56 @@ date: 2022-05-30 -> 2022-05-30 # times with timezones are removed since they're not supported by this library time: 20:26:52 -> 20:26:52 -time: 20:26:52.3 -> 20:26:52.3 -time: 20:26:52.36 -> 20:26:52.36 -time: 20:26:52.361 -> 20:26:52.361 -time: 20:26:52.361000 -> 20:26:52.361 +time: 20:26:52.3 -> 20:26:52.300000 +time: 20:26:52.36 -> 20:26:52.360000 +time: 20:26:52.361 -> 20:26:52.361000 +time: 20:26:52.361000 -> 20:26:52.361000 dt: 2022-05-30T20:26:52Z -> 2022-05-30T20:26:52Z -dt: 2022-05-30T20:26:52.3Z -> 2022-05-30T20:26:52.3Z -dt: 2022-05-30T20:26:52.36Z -> 2022-05-30T20:26:52.36Z -dt: 2022-05-30T20:26:52.361Z -> 2022-05-30T20:26:52.361Z -dt: 2022-05-30T20:26:52.361000Z -> 2022-05-30T20:26:52.361Z +dt: 2022-05-30T20:26:52.3Z -> 2022-05-30T20:26:52.300000Z +dt: 2022-05-30T20:26:52.36Z -> 2022-05-30T20:26:52.360000Z +dt: 2022-05-30T20:26:52.361Z -> 2022-05-30T20:26:52.361000Z +dt: 2022-05-30T20:26:52.361000Z -> 2022-05-30T20:26:52.361000Z dt: 2022-05-30T21:26:52+01:00 -> 2022-05-30T21:26:52+01:00 -dt: 2022-05-30T21:26:52.361+01:00 -> 2022-05-30T21:26:52.361+01:00 -dt: 2022-05-30T21:26:52.361000+01:00 -> 2022-05-30T21:26:52.361+01:00 +dt: 2022-05-30T21:26:52.361+01:00 -> 2022-05-30T21:26:52.361000+01:00 +dt: 2022-05-30T21:26:52.361000+01:00 -> 2022-05-30T21:26:52.361000+01:00 dt: 2022-05-30 21:26:52+01:00 -> 2022-05-30T21:26:52+01:00 -dt: 2022-05-30 21:26:52.3+01:00 -> 2022-05-30T21:26:52.3+01:00 -dt: 2022-05-30 21:26:52.36+01:00 -> 2022-05-30T21:26:52.36+01:00 -dt: 2022-05-30 21:26:52.361+01:00 -> 2022-05-30T21:26:52.361+01:00 -dt: 2022-05-30 21:26:52.361000+01:00 -> 2022-05-30T21:26:52.361+01:00 +dt: 2022-05-30 21:26:52.3+01:00 -> 2022-05-30T21:26:52.300000+01:00 +dt: 2022-05-30 21:26:52.36+01:00 -> 2022-05-30T21:26:52.360000+01:00 +dt: 2022-05-30 21:26:52.361+01:00 -> 2022-05-30T21:26:52.361000+01:00 +dt: 2022-05-30 21:26:52.361000+01:00 -> 2022-05-30T21:26:52.361000+01:00 dt: 2022-05-30 20:26:52Z -> 2022-05-30T20:26:52Z dt: 2022-05-30_20:26:52Z -> 2022-05-30T20:26:52Z dt: 2022-05-30 20:26:52z -> 2022-05-30T20:26:52Z dt: 2022-05-30_20:26:52z -> 2022-05-30T20:26:52Z -dt: 2022-05-30 20:26:52.3Z -> 2022-05-30T20:26:52.3Z -dt: 2022-05-30 20:26:52.36Z -> 2022-05-30T20:26:52.36Z -dt: 2022-05-30 20:26:52.361Z -> 2022-05-30T20:26:52.361Z -dt: 2022-05-30_20:26:52.361Z -> 2022-05-30T20:26:52.361Z -dt: 2022-05-30 20:26:52.361000Z -> 2022-05-30T20:26:52.361Z -dt: 2022-05-30_20:26:52.361000Z -> 2022-05-30T20:26:52.361Z -dt: 2022-05-30 20:26:52.361z -> 2022-05-30T20:26:52.361Z -dt: 2022-05-30_20:26:52.361z -> 2022-05-30T20:26:52.361Z -dt: 2022-05-30 20:26:52.361000z -> 2022-05-30T20:26:52.361Z -dt: 2022-05-30_20:26:52.361000z -> 2022-05-30T20:26:52.361Z +dt: 2022-05-30 20:26:52.3Z -> 2022-05-30T20:26:52.300000Z +dt: 2022-05-30 20:26:52.36Z -> 2022-05-30T20:26:52.360000Z +dt: 2022-05-30 20:26:52.361Z -> 2022-05-30T20:26:52.361000Z +dt: 2022-05-30_20:26:52.361Z -> 2022-05-30T20:26:52.361000Z +dt: 2022-05-30 20:26:52.361000Z -> 2022-05-30T20:26:52.361000Z +dt: 2022-05-30_20:26:52.361000Z -> 2022-05-30T20:26:52.361000Z +dt: 2022-05-30 20:26:52.361z -> 2022-05-30T20:26:52.361000Z +dt: 2022-05-30_20:26:52.361z -> 2022-05-30T20:26:52.361000Z +dt: 2022-05-30 20:26:52.361000z -> 2022-05-30T20:26:52.361000Z +dt: 2022-05-30_20:26:52.361000z -> 2022-05-30T20:26:52.361000Z dt: 2022-05-30 20:26:52-00:00 -> 2022-05-30T20:26:52Z -dt: 2022-05-30 20:26:52.361-00:00 -> 2022-05-30T20:26:52.361Z +dt: 2022-05-30 20:26:52.361-00:00 -> 2022-05-30T20:26:52.361000Z dt: 2022-05-30T20:26:52-00:00 -> 2022-05-30T20:26:52Z -dt: 2022-05-30T20:26:52.361-00:00 -> 2022-05-30T20:26:52.361Z +dt: 2022-05-30T20:26:52.361-00:00 -> 2022-05-30T20:26:52.361000Z dt: 2022-05-31T05:11:52+08:45 -> 2022-05-31T05:11:52+08:45 dt: 2022-05-30T20:26:52+00:00 -> 2022-05-30T20:26:52Z -dt: 2022-05-30T20:26:52.361+00:00 -> 2022-05-30T20:26:52.361Z +dt: 2022-05-30T20:26:52.361+00:00 -> 2022-05-30T20:26:52.361000Z # from https://github.com/python/cpython/blob/5849af7a80166e9e82040e082f22772bd7cf3061/Lib/test/datetimetester.py#L3104-L3226 # with invalid cases moved to values_err.txt dt: 2025-01-02T03:04 -> 2025-01-02T03:04:00 dt: 2025-01-02T03:04:05 -> 2025-01-02T03:04:05 -dt: 2025-01-02T03:04:05.6 -> 2025-01-02T03:04:05.6 -dt: 2025-01-02T03:04:05,6 -> 2025-01-02T03:04:05.6 -dt: 2025-01-02T03:04:05.678 -> 2025-01-02T03:04:05.678 +dt: 2025-01-02T03:04:05.6 -> 2025-01-02T03:04:05.600000 +dt: 2025-01-02T03:04:05,6 -> 2025-01-02T03:04:05.600000 +dt: 2025-01-02T03:04:05.678 -> 2025-01-02T03:04:05.678000 dt: 2025-01-02T03:04:05.678901 -> 2025-01-02T03:04:05.678901 dt: 2025-01-02T03:04:05,678901 -> 2025-01-02T03:04:05.678901 -dt: 2009-04-19T03:15:45.2345 -> 2009-04-19T03:15:45.2345 -dt: 2025-01-02T03:04:05,678 -> 2025-01-02T03:04:05.678 +dt: 2009-04-19T03:15:45.2345 -> 2009-04-19T03:15:45.234500 +dt: 2025-01-02T03:04:05,678 -> 2025-01-02T03:04:05.678000 dt: 2025-01-02T03:04:05Z -> 2025-01-02T03:04:05Z dt: 2025-01-02T03:05:06+0300 -> 2025-01-02T03:05:06+03:00 dt: 2025-01-02T03:05:06-0300 -> 2025-01-02T03:05:06-03:00 @@ -62,4 +62,4 @@ dt: 2020-06-01T04:05:06.111111-04:00 -> 2020-06-01T04:05:06.111111-04:00 dt: 2020-06-01T04:05:06.111111-0400 -> 2020-06-01T04:05:06.111111-04:00 dt: 2021-10-31T01:30:00.000000+01:00 -> 2021-10-31T01:30:00+01:00 dt: 2021-10-31T01:30:00.000000+0100 -> 2021-10-31T01:30:00+01:00 -dt: 2025-01-02T03:04:05,678+00:00 -> 2025-01-02T03:04:05.678Z +dt: 2025-01-02T03:04:05,678+00:00 -> 2025-01-02T03:04:05.678000Z