feat(helpers): parse HHMM timestamps

This commit is contained in:
xeruf 2024-12-18 14:10:03 +01:00
parent ae4a678d77
commit 1b065c434f
1 changed files with 53 additions and 9 deletions

View File

@ -1,5 +1,3 @@
use std::ops::Sub;
use chrono::LocalResult::Single; use chrono::LocalResult::Single;
use chrono::{DateTime, Local, NaiveTime, TimeDelta, TimeZone, Utc}; use chrono::{DateTime, Local, NaiveTime, TimeDelta, TimeZone, Utc};
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
@ -34,16 +32,24 @@ impl<T: TimeZone> ToTimestamp for DateTime<T> {
} }
} }
/// Parses the hour from a plain number in the String,
/// Parses the hour optionally with minute from a plain number in a String,
/// with max of max_future hours into the future. /// with max of max_future hours into the future.
// TODO parse HHMM as well
pub fn parse_hour(str: &str, max_future: i64) -> Option<DateTime<Local>> { pub fn parse_hour(str: &str, max_future: i64) -> Option<DateTime<Local>> {
str.parse::<u32>().ok().and_then(|hour| { parse_hour_after(str, Local::now() - TimeDelta::hours(24 - max_future))
let now = Local::now(); }
/// Parses the hour optionally with minute from a plain number in a String.
pub fn parse_hour_after<T: TimeZone>(str: &str, after: DateTime<T>) -> Option<DateTime<T>> {
str.parse::<u32>().ok().and_then(|number| {
#[allow(deprecated)] #[allow(deprecated)]
now.date().and_hms_opt(hour, 0, 0).map(|time| { after.date().and_hms_opt(
if time - now > TimeDelta::hours(max_future) { if number > 23 { number / 100 } else { number },
time.sub(TimeDelta::days(1)) if number > 23 { number % 100 } else { 0 },
0,
).map(|time| {
if time < after {
time + TimeDelta::days(1)
} else { } else {
time time
} }
@ -160,3 +166,41 @@ pub fn format_timestamp_relative_to(stamp: &Timestamp, reference: &Timestamp) ->
_ => format_timestamp_local(stamp), _ => format_timestamp_local(stamp),
} }
} }
mod test {
use super::*;
use chrono::{NaiveDate, NaiveDateTime, Timelike};
use interim::datetime::DateTime;
#[test]
fn parse_hours() {
let now = Local::now();
#[allow(deprecated)]
let date = now.date();
if now.hour() > 2 {
assert_eq!(
parse_hour("23", 22).unwrap(),
date.and_hms_opt(23, 0, 0).unwrap()
);
}
if now.hour() < 22 {
assert_eq!(
parse_hour("02", 2).unwrap(),
date.and_hms_opt(2, 0, 0).unwrap()
);
assert_eq!(
parse_hour("2301", 1).unwrap(),
(date - TimeDelta::days(1)).and_hms_opt(23, 01, 0).unwrap()
);
}
let date = NaiveDate::from_ymd_opt(2020, 10, 10).unwrap();
let time = Utc.from_utc_datetime(
&date.and_hms_opt(10, 1,0).unwrap()
);
assert_eq!(parse_hour_after("2201", time).unwrap(), Utc.from_utc_datetime(&date.and_hms_opt(22, 1, 0).unwrap()));
assert_eq!(parse_hour_after("10", time).unwrap(), Utc.from_utc_datetime(&(date + TimeDelta::days(1)).and_hms_opt(10, 0, 0).unwrap()));
// TODO test timezone offset issues
}
}