Skip to content

Commit a7061bc

Browse files
authored
Merge pull request #102 from jfinkels/parse-datetime-with-single-digit-offset
Parse datetimes with single digit timezone offset
2 parents 938aa96 + ea49dc9 commit a7061bc

File tree

1 file changed

+21
-11
lines changed

1 file changed

+21
-11
lines changed

src/lib.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ mod format {
7777
pub const YYYYMMDDHHMM_UTC_OFFSET: &str = "%Y%m%d%H%MUTC%z";
7878
pub const YYYYMMDDHHMM_ZULU_OFFSET: &str = "%Y%m%d%H%MZ%z";
7979
pub const YYYYMMDDHHMM_HYPHENATED_OFFSET: &str = "%Y-%m-%d %H:%M %z";
80+
pub const YYYYMMDDHHMMSS_HYPHENATED_OFFSET: &str = "%Y-%m-%d %H:%M:%S %#z";
8081
pub const YYYYMMDDHHMMS_T_SEP: &str = "%Y-%m-%dT%H:%M:%S";
8182
pub const UTC_OFFSET: &str = "UTC%#z";
8283
pub const ZULU_OFFSET: &str = "Z%#z";
@@ -154,9 +155,16 @@ pub fn parse_datetime_at_date<S: AsRef<str> + Clone>(
154155
// similar
155156

156157
// Formats with offsets don't require NaiveDateTime workaround
158+
//
159+
// HACK: if the string ends with a single digit preceded by a + or -
160+
// sign, then insert a 0 between the sign and the digit to make it
161+
// possible for `chrono` to parse it.
162+
let pattern = Regex::new(r"([\+-])(\d)$").unwrap();
163+
let s = pattern.replace(s.as_ref(), "${1}0${2}");
157164
for fmt in [
158165
format::YYYYMMDDHHMM_OFFSET,
159166
format::YYYYMMDDHHMM_HYPHENATED_OFFSET,
167+
format::YYYYMMDDHHMMSS_HYPHENATED_OFFSET,
160168
format::YYYYMMDDHHMM_UTC_OFFSET,
161169
format::YYYYMMDDHHMM_ZULU_OFFSET,
162170
] {
@@ -230,16 +238,7 @@ pub fn parse_datetime_at_date<S: AsRef<str> + Clone>(
230238
// offsets, so instead we replicate parse_date behaviour by getting
231239
// the current date with local, and create a date time string at midnight,
232240
// before trying offset suffixes
233-
//
234-
// HACK: if the string ends with a single digit preceded by a + or -
235-
// sign, then insert a 0 between the sign and the digit to make it
236-
// possible for `chrono` to parse it.
237-
let pattern = Regex::new(r"([\+-])(\d)$").unwrap();
238-
let ts = format!(
239-
"{}0000{}",
240-
date.format("%Y%m%d"),
241-
pattern.replace(s.as_ref(), "${1}0${2}")
242-
);
241+
let ts = format!("{}0000{}", date.format("%Y%m%d"), s);
243242
for fmt in [
244243
format::UTC_OFFSET,
245244
format::ZULU_OFFSET,
@@ -370,7 +369,7 @@ mod tests {
370369

371370
#[cfg(test)]
372371
mod offsets {
373-
use chrono::Local;
372+
use chrono::{Local, NaiveDate};
374373

375374
use crate::parse_datetime;
376375
use crate::ParseDateTimeError;
@@ -413,6 +412,17 @@ mod tests {
413412
Err(ParseDateTimeError::InvalidInput)
414413
);
415414
}
415+
416+
#[test]
417+
fn test_datetime_with_offset() {
418+
let actual = parse_datetime("1997-01-19 08:17:48 +0").unwrap();
419+
let expected = NaiveDate::from_ymd_opt(1997, 1, 19)
420+
.unwrap()
421+
.and_hms_opt(8, 17, 48)
422+
.unwrap()
423+
.and_utc();
424+
assert_eq!(actual, expected);
425+
}
416426
}
417427

418428
#[cfg(test)]

0 commit comments

Comments
 (0)