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