@@ -1,6 +1,6 @@ | |||
[package] | |||
name = "tzconvert" | |||
version = "1.0.0" | |||
version = "1.1.0" | |||
edition = "2018" | |||
authors = ["Jonathan Strong <jstrong@mmcxi.com>"] | |||
@@ -26,4 +26,4 @@ chrono-tz = { version = "0.5", features = ["serde"] } | |||
structopt = "0.3" | |||
regex = "1.5" | |||
lazy_static = "1.4" | |||
colored = "2" |
@@ -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 | |||
@@ -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<String>, | |||
/// 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<NaiveDate>, | |||
} | |||
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); | |||
} |
@@ -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<String>, | |||
/// 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<NaiveDate>, | |||
} | |||
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); | |||
} |
@@ -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<hr>\d{1,2})\s?(?P<ampm>(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<NaiveDate>) { | |||
pub fn convert(from: &str, to: &str, time: &str, day: Option<String>, date: Option<NaiveDate>) { | |||
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<NaiveDate>) { | |||
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<NaiveDate>) { | |||
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<NaiveDate>) { | |||
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!(); | |||
} | |||
@@ -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<String>, | |||
/// 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<NaiveDate>, | |||
} | |||
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); | |||
} |