some date parsing magic
This commit is contained in:
parent
4980b3df67
commit
a56df91b58
|
@ -22,7 +22,8 @@ fn local_to_utc(t: DateTime<Utc>) -> error::Result<DateTime<Utc>> {
|
|||
LocalResult::Single(t) => t,
|
||||
LocalResult::Ambiguous(t1, t2) => return Err(error::Error::AmbiguousLocalTime {
|
||||
orig: t.naive_utc().to_string(),
|
||||
t1, t2,
|
||||
t1: t1.naive_local(),
|
||||
t2: t2.naive_local(),
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ pub enum Error {
|
|||
#[error("Trying to parse {orig} as a time in your timezone led to the ambiguous results {t1} and {t2}")]
|
||||
AmbiguousLocalTime {
|
||||
orig: String,
|
||||
t1: DateTime<Local>,
|
||||
t2: DateTime<Local>,
|
||||
t1: NaiveDateTime,
|
||||
t2: NaiveDateTime,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use chrono::{DateTime, Utc, Local, TimeZone, LocalResult};
|
||||
use chrono::{DateTime, Utc, Local, TimeZone, LocalResult, FixedOffset};
|
||||
use regex::Regex;
|
||||
|
||||
use crate::error::{Result, Error};
|
||||
|
@ -17,18 +17,64 @@ pub fn parse_time(input: &str) -> Result<DateTime<Utc>> {
|
|||
(?P<minute>\d{2})? # the minute, optional
|
||||
(. # a separator
|
||||
(?P<second>\d{2}))?)?)? # the second, optional, implies minute
|
||||
(?P<offset>(?P<utc>Z)|(?P<fixedoffset>(\+|-)\d{2}:\d{2}))? # the offset, optional
|
||||
(?P<offset>
|
||||
(?P<utc>Z)|((?P<sign>\+|-)(?P<ohour>\d{1,2}):(?P<omin>\d{2}))
|
||||
)? # the offset, optional
|
||||
").unwrap();
|
||||
|
||||
if let Some(caps) = re.captures(input) {
|
||||
if let Some(_) = caps.name("offset") {
|
||||
return if let Some(_) = caps.name("offset") {
|
||||
// start with a specific offset or utc
|
||||
if let Some(_) = caps.name("utc") {
|
||||
// start with utc
|
||||
unimplemented!()
|
||||
let try_date = Utc.ymd_opt(
|
||||
(&caps["year"]).parse().unwrap(),
|
||||
(&caps["month"]).parse().unwrap(),
|
||||
(&caps["day"]).parse().unwrap(),
|
||||
).and_hms_opt(
|
||||
caps.name("hour").map(|m| m.as_str().parse().unwrap()).unwrap_or(0),
|
||||
caps.name("minute").map(|m| m.as_str().parse().unwrap()).unwrap_or(0),
|
||||
caps.name("second").map(|m| m.as_str().parse().unwrap()).unwrap_or(0),
|
||||
);
|
||||
|
||||
match try_date {
|
||||
LocalResult::None => Err(Error::NoneLocalTime(input.into())),
|
||||
LocalResult::Single(t) => Ok(t),
|
||||
LocalResult::Ambiguous(t1, t2) => Err(Error::AmbiguousLocalTime {
|
||||
orig: input.into(),
|
||||
t1: t1.naive_utc(),
|
||||
t2: t2.naive_utc(),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
// start with an offset
|
||||
unimplemented!()
|
||||
let mut offset: i32 = (&caps["ohour"]).parse::<i32>().unwrap() * 60 * 60;
|
||||
offset += (&caps["omin"]).parse::<i32>().unwrap() * 60;
|
||||
|
||||
let fo = if &caps["sign"] == "+" {
|
||||
FixedOffset::east(offset)
|
||||
} else {
|
||||
FixedOffset::west(offset)
|
||||
};
|
||||
|
||||
let try_date = fo.ymd_opt(
|
||||
(&caps["year"]).parse().unwrap(),
|
||||
(&caps["month"]).parse().unwrap(),
|
||||
(&caps["day"]).parse().unwrap(),
|
||||
).and_hms_opt(
|
||||
caps.name("hour").map(|m| m.as_str().parse().unwrap()).unwrap_or(0),
|
||||
caps.name("minute").map(|m| m.as_str().parse().unwrap()).unwrap_or(0),
|
||||
caps.name("second").map(|m| m.as_str().parse().unwrap()).unwrap_or(0),
|
||||
);
|
||||
|
||||
match try_date {
|
||||
LocalResult::None => Err(Error::NoneLocalTime(input.into())),
|
||||
LocalResult::Single(t) => Ok(Utc.from_utc_datetime(&t.naive_utc())),
|
||||
LocalResult::Ambiguous(t1, t2) => Err(Error::AmbiguousLocalTime {
|
||||
orig: input.into(),
|
||||
t1: t1.naive_utc(),
|
||||
t2: t2.naive_utc(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// start with a local time
|
||||
|
@ -42,15 +88,16 @@ pub fn parse_time(input: &str) -> Result<DateTime<Utc>> {
|
|||
caps.name("second").map(|m| m.as_str().parse().unwrap()).unwrap_or(0),
|
||||
);
|
||||
|
||||
return match try_date {
|
||||
match try_date {
|
||||
LocalResult::None => Err(Error::NoneLocalTime(input.into())),
|
||||
LocalResult::Single(t) => Ok(Utc.from_utc_datetime(&t.naive_utc())),
|
||||
LocalResult::Ambiguous(t1, t2) => Err(Error::AmbiguousLocalTime {
|
||||
orig: input.into(),
|
||||
t1, t2,
|
||||
t1: t1.naive_utc(),
|
||||
t2: t2.naive_utc(),
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Err(Error::DateTimeParseError(input.into()))
|
||||
|
@ -88,10 +135,24 @@ mod tests {
|
|||
assert_eq!(parse_time("11:36:35").unwrap(), now.date().and_hms(16, 36, 35));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_hour_with_timezone() {
|
||||
std::env::set_var("TZ", "America/Mexico_City");
|
||||
|
||||
let now = Utc::now();
|
||||
|
||||
assert_eq!(parse_time("11:36Z").unwrap(), now.date().and_hms(11, 36, 0));
|
||||
assert_eq!(parse_time("11:36:35z").unwrap(), now.date().and_hms(11, 36, 35));
|
||||
|
||||
assert_eq!(parse_time("11:36-5:00").unwrap(), now.date().and_hms(16, 36, 0));
|
||||
assert_eq!(parse_time("11:36:35+5:00").unwrap(), now.date().and_hms(6, 36, 35));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_with_specified_timezone() {
|
||||
assert_eq!(parse_time("2021-05-21T11:36:12Z").unwrap(), Utc.ymd(2021, 5, 21).and_hms(11, 36, 12));
|
||||
assert_eq!(parse_time("2021-05-21T11:36:12-3:00").unwrap(), Utc.ymd(2021, 5, 21).and_hms(14, 36, 12));
|
||||
assert_eq!(parse_time("2021-05-21T11:36:12+3:00").unwrap(), Utc.ymd(2021, 5, 21).and_hms(8, 36, 12));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in New Issue