Merge pull request #223 from yuankunzhang/support-timezone-offset-larger-than-24-hour

fix: support timezone offsets that exceed 24-hour range
This commit is contained in:
Daniel Hofstetter
2025-08-24 15:29:11 +02:00
committed by GitHub
4 changed files with 31 additions and 5 deletions
+4 -2
View File
@@ -245,8 +245,10 @@ impl DateTimeBuilder {
.ok()?;
}
if let Some(offset) = &self.timezone {
dt = dt.datetime().to_zoned(offset.try_into().ok()?).ok()?;
if let Some(offset) = self.timezone {
let (offset, hour_adjustment) = offset.normalize();
dt = dt.checked_add(Span::new().hours(hour_adjustment)).ok()?;
dt = dt.datetime().to_zoned((&offset).try_into().ok()?).ok()?;
}
Some(dt)
+24
View File
@@ -84,6 +84,30 @@ impl Offset {
minutes,
}
}
/// Normalize the offset so that the hour field is within the accepted range.
///
/// - If the hour field is less than 24, or exactly 24 with a zero minute,
/// the offset is already normalized, and the function returns the offset
/// itself along with a zero hour adjustment.
/// - Otherwise, the hour field is reduced to 23 while preserving the minute
/// field, and the function returns the normalized offset along with the
/// hour adjustment needed to reach the original offset.
pub(super) fn normalize(self) -> (Offset, i8) {
if self.hours < 24 || (self.hours == 24 && self.minutes == 0) {
return (self, 0);
}
let hour_adjustment = (self.hours as i8 - 23) * if self.negative { 1 } else { -1 };
(
Offset {
negative: self.negative,
hours: 23,
minutes: self.minutes,
},
hour_adjustment,
)
}
}
impl TryFrom<(bool, u8, u8)> for Offset {
+1 -1
View File
@@ -278,7 +278,7 @@ mod tests {
#[test]
fn offset_overflow() {
assert!(parse_datetime("m+14").is_err());
assert!(parse_datetime("m+25").is_err());
assert!(parse_datetime("24:00").is_err());
}
}
+2 -2
View File
@@ -90,12 +90,12 @@ fn test_time_correction(#[case] input: &str, #[case] expected: &str) {
#[case::minus_12("12:34:56-12:00", "2022-06-11 00:34:56")]
#[case::plus_1259("12:34:56+12:59", "2022-06-09 23:35:56")]
#[case::minus_1259("12:34:56-12:59", "2022-06-11 01:33:56")]
/* TODO: https://github.com/uutils/parse_datetime/issues/149
#[case::plus_24("12:34:56+24:00", "2022-06-09 12:34:56")]
#[case::minus_24("12:34:56-24:00", "2022-06-11 12:34:56")]
#[case::plus_13("11:34:56+13:00", "2022-06-09 22:34:56")]
#[case::minus_13("12:34:56-13:00", "2022-06-11 01:34:56")]
*/
#[case::plus_36("12:34:56 m+24", "2022-06-09 00:34:56")]
#[case::minus_36("12:34:56 y-24:00", "2022-06-12 00:34:56")]
fn test_time_correction_with_overflow(#[case] input: &str, #[case] expected: &str) {
let now = "2022-06-10 00:00:00"
.parse::<DateTime>()