diff --git a/src/parse_time_only_str.rs b/src/parse_time_only_str.rs index e909216..ef0f814 100644 --- a/src/parse_time_only_str.rs +++ b/src/parse_time_only_str.rs @@ -7,11 +7,75 @@ mod time_only_formats { pub const TWELVEHOUR: &str = "%r"; } +/// Convert a military time zone string to a time zone offset. +/// +/// Military time zones are the letters A through Z except J. They are +/// described in RFC 5322. +fn to_offset(tz: &str) -> Option { + let hour = match tz { + "A" => 1, + "B" => 2, + "C" => 3, + "D" => 4, + "E" => 5, + "F" => 6, + "G" => 7, + "H" => 8, + "I" => 9, + "K" => 10, + "L" => 11, + "M" => 12, + "N" => -1, + "O" => -2, + "P" => -3, + "Q" => -4, + "R" => -5, + "S" => -6, + "T" => -7, + "U" => -8, + "V" => -9, + "W" => -10, + "X" => -11, + "Y" => -12, + "Z" => 0, + _ => return None, + }; + let offset_in_sec = hour * 3600; + FixedOffset::east_opt(offset_in_sec) +} + +/// Parse a time string without an offset and apply an offset to it. +/// +/// Multiple formats are attempted when parsing the string. +fn parse_time_with_offset_multi( + date: DateTime, + offset: FixedOffset, + s: &str, +) -> Option> { + for fmt in [ + time_only_formats::HH_MM, + time_only_formats::HH_MM_SS, + time_only_formats::TWELVEHOUR, + ] { + let parsed = match NaiveTime::parse_from_str(s, fmt) { + Ok(t) => t, + Err(_) => continue, + }; + let parsed_dt = date.date_naive().and_time(parsed); + match offset.from_local_datetime(&parsed_dt).single() { + Some(dt) => return Some(dt), + None => continue, + } + } + None +} + pub(crate) fn parse_time_only(date: DateTime, s: &str) -> Option> { let re = Regex::new(r"^(?