Show More
@@ -4,7 +4,7 use std::collections::BTreeMap; | |||
|
4 | 4 | use std::fmt::{Debug, Formatter}; |
|
5 | 5 | use std::{iter, str}; |
|
6 | 6 | |
|
7 |
use chrono::{DateTime, FixedOffset, |
|
|
7 | use chrono::{DateTime, FixedOffset, Utc}; | |
|
8 | 8 | use itertools::{Either, Itertools}; |
|
9 | 9 | |
|
10 | 10 | use crate::errors::HgError; |
@@ -339,7 +339,7 fn parse_timestamp( | |||
|
339 | 339 | HgError::corrupted(format!("failed to parse timestamp: {e}")) |
|
340 | 340 | }) |
|
341 | 341 | .and_then(|secs| { |
|
342 |
|
|
|
342 | DateTime::from_timestamp(secs, 0).ok_or_else(|| { | |
|
343 | 343 | HgError::corrupted(format!( |
|
344 | 344 | "integer timestamp out of valid range: {secs}" |
|
345 | 345 | )) |
@@ -364,14 +364,17 fn parse_timestamp( | |||
|
364 | 364 | let timezone = FixedOffset::west_opt(timezone_secs) |
|
365 | 365 | .ok_or_else(|| HgError::corrupted("timezone offset out of bounds"))?; |
|
366 | 366 | |
|
367 |
Ok(DateTime::from_naive_utc_and_offset( |
|
|
367 | Ok(DateTime::from_naive_utc_and_offset( | |
|
368 | timestamp_utc.naive_utc(), | |
|
369 | timezone, | |
|
370 | )) | |
|
368 | 371 | } |
|
369 | 372 | |
|
370 | 373 | /// Attempt to parse the given string as floating-point timestamp, and |
|
371 | 374 | /// convert the result into a `chrono::NaiveDateTime`. |
|
372 | 375 | fn parse_float_timestamp( |
|
373 | 376 | timestamp_str: &str, |
|
374 |
) -> Result< |
|
|
377 | ) -> Result<DateTime<Utc>, HgError> { | |
|
375 | 378 | let timestamp = timestamp_str.parse::<f64>().map_err(|e| { |
|
376 | 379 | HgError::corrupted(format!("failed to parse timestamp: {e}")) |
|
377 | 380 | })?; |
@@ -399,7 +402,7 fn parse_float_timestamp( | |||
|
399 | 402 | // precision with present-day timestamps.) |
|
400 | 403 | let nsecs = (subsecs * 1_000_000_000.0) as u32; |
|
401 | 404 | |
|
402 |
|
|
|
405 | DateTime::from_timestamp(secs, nsecs).ok_or_else(|| { | |
|
403 | 406 | HgError::corrupted(format!( |
|
404 | 407 | "float timestamp out of valid range: {timestamp}" |
|
405 | 408 | )) |
@@ -647,19 +650,19 message", | |||
|
647 | 650 | fn test_parse_float_timestamp() { |
|
648 | 651 | let test_cases = [ |
|
649 | 652 | // Zero should map to the UNIX epoch. |
|
650 | ("0.0", "1970-01-01 00:00:00"), | |
|
653 | ("0.0", "1970-01-01 00:00:00 UTC"), | |
|
651 | 654 | // Negative zero should be the same as positive zero. |
|
652 | ("-0.0", "1970-01-01 00:00:00"), | |
|
655 | ("-0.0", "1970-01-01 00:00:00 UTC"), | |
|
653 | 656 | // Values without fractional components should work like integers. |
|
654 | 657 | // (Assuming the timestamp is within the limits of f64 precision.) |
|
655 | ("1115154970.0", "2005-05-03 21:16:10"), | |
|
658 | ("1115154970.0", "2005-05-03 21:16:10 UTC"), | |
|
656 | 659 | // We expect some loss of precision in the fractional component |
|
657 | 660 | // when parsing arbitrary floating-point values. |
|
658 | ("1115154970.123456789", "2005-05-03 21:16:10.123456716"), | |
|
661 | ("1115154970.123456789", "2005-05-03 21:16:10.123456716 UTC"), | |
|
659 | 662 | // But representable f64 values should parse losslessly. |
|
660 | ("1115154970.123456716", "2005-05-03 21:16:10.123456716"), | |
|
663 | ("1115154970.123456716", "2005-05-03 21:16:10.123456716 UTC"), | |
|
661 | 664 | // Negative fractional components are subtracted from the epoch. |
|
662 | ("-1.333", "1969-12-31 23:59:58.667"), | |
|
665 | ("-1.333", "1969-12-31 23:59:58.667 UTC"), | |
|
663 | 666 | ]; |
|
664 | 667 | |
|
665 | 668 | for (input, expected) in test_cases { |
General Comments 0
You need to be logged in to leave comments.
Login now