|
- use chrono::prelude::*;
- use chrono_tz::Tz;
-
- lazy_static::lazy_static! {
- static ref HOUR_AMPM: regex::Regex = regex::Regex::new(r#"(?P<hr>\d{1,2})\s?(?P<ampm>(am|pm|AM|PM))"#).unwrap();
- static ref HOUR_MINUTE_AMPM: regex::Regex = regex::Regex::new(r#"(?P<hr>\d{1,2}):(?P<minute>\d{2})\s?(?P<ampm>(am|pm|AM|PM))"#).unwrap();
- }
-
- fn parse_time(time_input: &str) -> NaiveTime {
- let time: String = time_input.split_whitespace().collect::<Vec<_>>().join("");
- match NaiveTime::parse_from_str(&time, "%H:%M") {
- Ok(t) => return t,
- Err(_e) => {}
- }
-
- if HOUR_MINUTE_AMPM.is_match(&time) {
- return NaiveTime::parse_from_str(&time, "%I:%M%p").unwrap();
- }
-
- let t2 = HOUR_AMPM.replace(&time, "$hr:00$ampm");
-
- match NaiveTime::parse_from_str(&t2, "%I:%M%p") {
- Ok(t) => return t,
- Err(_e) => {}
- }
-
- panic!("failed to parse time -- try HH:MM format (input = '{}')", time)
- }
-
- fn convert_common_tz_abbrs(tz: &str) -> &str {
- let tz = tz.trim();
- if tz.eq_ignore_ascii_case("EST") { return "America/New_York" }
- if tz.eq_ignore_ascii_case("EPT") { return "America/New_York" }
- if tz.eq_ignore_ascii_case("EDT") { return "America/New_York" }
- if tz.eq_ignore_ascii_case("US/Eastern") { return "America/New_York" }
- if tz.eq_ignore_ascii_case("CET") { return "Europe/Brussels" }
- if tz.eq_ignore_ascii_case("CEST") { return "Europe/Brussels" }
- if tz.eq_ignore_ascii_case("Brussels") { return "Europe/Brussels" }
-
- tz
- }
-
- pub fn convert(from: &str, to: &str, time: &str, date: Option<NaiveDate>) {
- let from = convert_common_tz_abbrs(from);
- let to = convert_common_tz_abbrs(to);
-
- let fromtz: Tz = match from.parse() {
- Ok(tz) => tz,
- Err(e) => panic!("failed to parse from tz: {} (input = '{}')", e, from),
- };
-
- let totz: Tz = match to.parse() {
- Ok(tz) => tz,
- Err(e) => panic!("failed to parse to tz: {} (input = '{}')", e, to),
- };
-
- let tm = parse_time(time);
-
- let dt: Date<Tz> = match date {
- Some(dt) => fromtz.from_local_date(&dt).unwrap(),
- None => Utc::today().with_timezone(&fromtz),
- };
-
- let src = dt.and_time(tm).unwrap();
-
- let dst = src.with_timezone(&totz);
-
- let fromtz_str = fromtz.to_string();
- let totz_str = totz.to_string();
- let n_spaces = std::cmp::max(fromtz_str.len(), totz_str.len());
-
- let indent = " ";
- println!();
- println!("{} {} ... {} ... {}",
- indent,
- pad_spaces(fromtz_str, n_spaces),
- src.format("%a, %b %e"),
- src.format("%l:%M%P"),
- );
-
- println!();
-
- println!("{} {} ... {} ... {}",
- indent,
- pad_spaces(totz_str, n_spaces),
- dst.format("%a, %b %e"),
- dst.format("%l:%M%P"),
- );
-
- println!();
- }
-
- fn pad_spaces<S: ToString>(s: S, n: usize) -> String {
- let s = s.to_string();
- let mut out = String::with_capacity(n);
- out.push_str(&s);
- while out.len() < n {
- out.push_str(" ");
- }
- out
- }
-
- #[test]
- fn parse_time_like_2pm() {
- dbg!(parse_time("2pm"));
- assert_eq!(parse_time("2pm"), NaiveTime::from_hms(14, 0, 0));
- assert_eq!(parse_time("7am"), NaiveTime::from_hms(7, 0, 0));
- dbg!(HOUR_AMPM.replace("8:30am", "$hr:00$ampm"));
- assert_eq!(parse_time("8:30am"), NaiveTime::from_hms(8, 30, 0));
- }
|