From 031d8ac91f4bdb0ced26aa245e10ba16c366358d Mon Sep 17 00:00:00 2001 From: Jonathan Strong Date: Thu, 26 Aug 2021 10:05:40 -0400 Subject: [PATCH] adds day of week parameter (i.e. cet2est 2pm tue) --- Cargo.toml | 4 ++-- justfile | 24 ++++++++++++++++++++++++ src/cet2est.rs | 33 ++++++++++++++++++++++++++++----- src/est2cet.rs | 35 +++++++++++++++++++++++++++++------ src/lib.rs | 28 ++++++++++++++++++++++++---- src/main.rs | 27 +++++++++++++++++++++------ 6 files changed, 128 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3a19b2e..1f57358 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tzconvert" -version = "1.0.0" +version = "1.1.0" edition = "2018" authors = ["Jonathan Strong "] @@ -26,4 +26,4 @@ chrono-tz = { version = "0.5", features = ["serde"] } structopt = "0.3" regex = "1.5" lazy_static = "1.4" - +colored = "2" diff --git a/justfile b/justfile index e975e09..49e4bc8 100644 --- a/justfile +++ b/justfile @@ -13,4 +13,28 @@ debug-build: cargo build --bin cet2est cargo build --bin est2cet +send-release remote-machine: release-build + scp -C target/release/tzconvert {{remote-machine}}:~/.cargo/bin + scp -C target/release/cet2est {{remote-machine}}:~/.cargo/bin + scp -C target/release/est2cet {{remote-machine}}:~/.cargo/bin + +cargo +args: + cargo {{args}} + +run-examples: debug-build + ./target/debug/tzconvert CET EST 2pm + ./target/debug/tzconvert EST CET 1:30pm tue + ./target/debug/tzconvert Africa/Timbuktu America/Jamaica 18:30 --date 2021-11-03 + ./target/debug/tzconvert Africa/Timbuktu America/Jamaica 18:30 sat --date 2021-11-03 + ./target/debug/cet2est 2pm + ./target/debug/cet2est 1:30pm tue + ./target/debug/cet2est 14:15 -d 2021-11-03 + ./target/debug/cet2est 14:15 tue -d 2021-11-03 + ./target/debug/est2cet 2pm + ./target/debug/est2cet 1:30pm tue + ./target/debug/est2cet 14:15 -d 2021-11-03 + ./target/debug/est2cet 14:15 tue -d 2021-11-03 + + + diff --git a/src/cet2est.rs b/src/cet2est.rs index 34efd20..33b4da8 100644 --- a/src/cet2est.rs +++ b/src/cet2est.rs @@ -1,19 +1,42 @@ use structopt::StructOpt; use chrono::prelude::*; +/// convert CET time to EST +/// +/// examples: +/// +/// - cet2est 2pm +/// +/// - cet2est 1:30pm thu +/// +/// - cet2est 14:15 -d 2021-11-03 +/// #[derive(StructOpt, Debug)] #[structopt(author = env!("CARGO_PKG_AUTHORS"))] struct Opt { - /// time to convert + /// time to convert (%H:%M or %I[:%M]%p) #[structopt(value_name = "TIME")] time: String, - /// specify the date on which the time lies. defaults to today. - #[structopt(long, short)] + /// optional: specify day of week the time lies, relative to today. + /// + /// this will always result in a DATE greater than or equal to + /// today (in FROM TIMEZONE). + /// + /// example: if today is Thursday, Aug. 26, passing DAY OF WEEK "Friday"/"fri" + /// will result in a DATE of Friday, Aug. 27. + #[structopt(value_name = "DAY OF WEEK")] + day: Option, + + /// optional: specify date the time lies. defaults to today. + /// + /// when DAY OF WEEK argument is also specified, DAY OF WEEK will be picked relative + /// to DATE (i.e. the next occuring instance of, on or following DATE). + #[structopt(long, short, value_name = "DATE")] date: Option, } fn main() { - let Opt { time, date } = Opt::from_args(); - tzconvert::convert("Europe/Brussels", "EST", &time, date); + let Opt { time, date, day } = Opt::from_args(); + tzconvert::convert("Europe/Brussels", "America/New_York", &time, day, date); } diff --git a/src/est2cet.rs b/src/est2cet.rs index 504d9dc..8181f6a 100644 --- a/src/est2cet.rs +++ b/src/est2cet.rs @@ -1,19 +1,42 @@ use structopt::StructOpt; use chrono::prelude::*; +/// convert EST time to CET +/// +/// examples: +/// +/// - est2cet 2pm +/// +/// - est2cet 1:30pm thu +/// +/// - est2cet 14:15 -d 2021-11-03 +/// #[derive(StructOpt, Debug)] #[structopt(author = env!("CARGO_PKG_AUTHORS"))] struct Opt { - /// time to convert - #[structopt(value_name = "HH:MM")] + /// time to convert (%H:%M or %I[:%M]%p) + #[structopt(value_name = "TIME")] time: String, - /// specify the date on which the time lies. defaults to today. - #[structopt(long, short)] + /// optional: specify day of week the time lies, relative to today. + /// + /// this will always result in a DATE greater than or equal to + /// today (in FROM TIMEZONE). + /// + /// example: if today is Thursday, Aug. 26, passing DAY OF WEEK "Friday"/"fri" + /// will result in a DATE of Friday, Aug. 27. + #[structopt(value_name = "DAY OF WEEK")] + day: Option, + + /// optional: specify date the time lies. defaults to today. + /// + /// when DAY OF WEEK argument is also specified, DAY OF WEEK will be picked relative + /// to DATE (i.e. the next occuring instance of, on or following DATE). + #[structopt(long, short, value_name = "DATE")] date: Option, } fn main() { - let Opt { time, date } = Opt::from_args(); - tzconvert::convert("EST", "Europe/Brussels", &time, date); + let Opt { time, date, day } = Opt::from_args(); + tzconvert::convert("America/New_York", "Europe/Brussels", &time, day, date); } diff --git a/src/lib.rs b/src/lib.rs index 4b19eff..010fdc4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,7 @@ +use std::str::FromStr; use chrono::prelude::*; use chrono_tz::Tz; +use colored::*; lazy_static::lazy_static! { static ref HOUR_AMPM: regex::Regex = regex::Regex::new(r#"(?P
\d{1,2})\s?(?P(am|pm|AM|PM))"#).unwrap(); @@ -40,7 +42,7 @@ fn convert_common_tz_abbrs(tz: &str) -> &str { tz } -pub fn convert(from: &str, to: &str, time: &str, date: Option) { +pub fn convert(from: &str, to: &str, time: &str, day: Option, date: Option) { let from = convert_common_tz_abbrs(from); let to = convert_common_tz_abbrs(to); @@ -61,6 +63,23 @@ pub fn convert(from: &str, to: &str, time: &str, date: Option) { None => Utc::today().with_timezone(&fromtz), }; + let dt = match day { + Some(day_str) => { + let target_day_of_week: Weekday = Weekday::from_str(&day_str) + .map_err(|e| { + eprintln!("failed to parse day (input = '{}')", day_str); + e + }).unwrap(); + let mut cur = dt; + while cur.weekday() != target_day_of_week { + cur = cur.succ(); + } + cur + } + + None => dt, + }; + let src = dt.and_time(tm).unwrap(); let dst = src.with_timezone(&totz); @@ -71,7 +90,7 @@ pub fn convert(from: &str, to: &str, time: &str, date: Option) { let indent = " "; println!(); - println!("{} {} ... {} ... {}", + println!("{}{} ... {} ... {}", indent, pad_spaces(fromtz_str, n_spaces), src.format("%a, %b %e"), @@ -80,13 +99,14 @@ pub fn convert(from: &str, to: &str, time: &str, date: Option) { println!(); - println!("{} {} ... {} ... {}", + let dst_line = format!("{}{} ... {} ... {}", indent, pad_spaces(totz_str, n_spaces), dst.format("%a, %b %e"), - dst.format("%l:%M%P"), + dst.format("%l:%M%P").to_string(), ); + println!("{}", dst_line.bold()); println!(); } diff --git a/src/main.rs b/src/main.rs index 323f0fe..e20e4a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,10 +3,12 @@ use chrono::prelude::*; /// timezone converter /// -/// Examples: +/// examples: /// /// - tzconvert CET EST 2pm /// +/// - tzconvert EST CET 1:30pm thu +/// /// - tzconvert Africa/Timbuktu America/Jamaica 18:30 --date 2021-11-03 /// #[derive(StructOpt, Debug)] @@ -18,16 +20,29 @@ struct Opt { /// destination time zone #[structopt(value_name = "TO TIMEZONE")] to: String, - /// time to convert (HH:MM or HH[:MM]am/HH[:MM]pm) + /// time to convert (%H:%M or %I[:%M]%p) #[structopt(value_name = "TIME")] time: String, - /// specify the date on which the time lies; defaults to today - #[structopt(long, short)] + /// optional: specify day of week the time lies, relative to today. + /// + /// this will always result in a DATE greater than or equal to + /// today (in FROM TIMEZONE). + /// + /// example: if today is Thursday, Aug. 26, passing DAY OF WEEK "Friday"/"fri" + /// will result in a DATE of Friday, Aug. 27. + #[structopt(value_name = "DAY OF WEEK")] + day: Option, + + /// optional: specify date the time lies. defaults to today. + /// + /// when DAY OF WEEK argument is also specified, DAY OF WEEK will be picked relative + /// to DATE (i.e. the next occuring instance of, on or following DATE). + #[structopt(long, short, value_name = "DATE")] date: Option, } fn main() { - let Opt { from, to, time, date } = Opt::from_args(); - tzconvert::convert(&from, &to, &time, date); + let Opt { from, to, time, date, day } = Opt::from_args(); + tzconvert::convert(&from, &to, &time, day, date); }