Skip to content

Commit 4db8bf4

Browse files
authored
Merge pull request #223 from yuankunzhang/support-timezone-offset-larger-than-24-hour
fix: support timezone offsets that exceed 24-hour range
2 parents a0f1376 + 84d27e6 commit 4db8bf4

File tree

4 files changed

+31
-5
lines changed

4 files changed

+31
-5
lines changed

src/items/builder.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,10 @@ impl DateTimeBuilder {
245245
.ok()?;
246246
}
247247

248-
if let Some(offset) = &self.timezone {
249-
dt = dt.datetime().to_zoned(offset.try_into().ok()?).ok()?;
248+
if let Some(offset) = self.timezone {
249+
let (offset, hour_adjustment) = offset.normalize();
250+
dt = dt.checked_add(Span::new().hours(hour_adjustment)).ok()?;
251+
dt = dt.datetime().to_zoned((&offset).try_into().ok()?).ok()?;
250252
}
251253

252254
Some(dt)

src/items/timezone.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,30 @@ impl Offset {
8484
minutes,
8585
}
8686
}
87+
88+
/// Normalize the offset so that the hour field is within the accepted range.
89+
///
90+
/// - If the hour field is less than 24, or exactly 24 with a zero minute,
91+
/// the offset is already normalized, and the function returns the offset
92+
/// itself along with a zero hour adjustment.
93+
/// - Otherwise, the hour field is reduced to 23 while preserving the minute
94+
/// field, and the function returns the normalized offset along with the
95+
/// hour adjustment needed to reach the original offset.
96+
pub(super) fn normalize(self) -> (Offset, i8) {
97+
if self.hours < 24 || (self.hours == 24 && self.minutes == 0) {
98+
return (self, 0);
99+
}
100+
101+
let hour_adjustment = (self.hours as i8 - 23) * if self.negative { 1 } else { -1 };
102+
(
103+
Offset {
104+
negative: self.negative,
105+
hours: 23,
106+
minutes: self.minutes,
107+
},
108+
hour_adjustment,
109+
)
110+
}
87111
}
88112

89113
impl TryFrom<(bool, u8, u8)> for Offset {

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ mod tests {
278278

279279
#[test]
280280
fn offset_overflow() {
281-
assert!(parse_datetime("m+14").is_err());
281+
assert!(parse_datetime("m+25").is_err());
282282
assert!(parse_datetime("24:00").is_err());
283283
}
284284
}

tests/time.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,12 @@ fn test_time_correction(#[case] input: &str, #[case] expected: &str) {
9090
#[case::minus_12("12:34:56-12:00", "2022-06-11 00:34:56")]
9191
#[case::plus_1259("12:34:56+12:59", "2022-06-09 23:35:56")]
9292
#[case::minus_1259("12:34:56-12:59", "2022-06-11 01:33:56")]
93-
/* TODO: https://github.com/uutils/parse_datetime/issues/149
9493
#[case::plus_24("12:34:56+24:00", "2022-06-09 12:34:56")]
9594
#[case::minus_24("12:34:56-24:00", "2022-06-11 12:34:56")]
9695
#[case::plus_13("11:34:56+13:00", "2022-06-09 22:34:56")]
9796
#[case::minus_13("12:34:56-13:00", "2022-06-11 01:34:56")]
98-
*/
97+
#[case::plus_36("12:34:56 m+24", "2022-06-09 00:34:56")]
98+
#[case::minus_36("12:34:56 y-24:00", "2022-06-12 00:34:56")]
9999
fn test_time_correction_with_overflow(#[case] input: &str, #[case] expected: &str) {
100100
let now = "2022-06-10 00:00:00"
101101
.parse::<DateTime>()

0 commit comments

Comments
 (0)