#![allow(unused)] use std::str::FromStr; use chrono::{DateTime, Utc, NaiveDateTime, TimeZone}; const ONE_SECOND: u64 = 1_000_000_000_u64; fn nanos(utc: DateTime) -> u64 { (utc.timestamp() as u64) * 1_000_000_000_u64 + (utc.timestamp_subsec_nanos() as u64) } fn get_time() -> (i64, i32) { let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 }; unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut tv); } (tv.tv_sec as i64, tv.tv_nsec as i32) } fn timespec_to_utc(sec: i64, nsec: i32) -> DateTime { let naive = NaiveDateTime::from_timestamp(sec, nsec as u32); DateTime::from_utc(naive, Utc) } fn timespec_to_nanos(sec: i64, nsec: i32) -> u64 { (sec as u64) * ONE_SECOND + (nsec as u64) } fn nanos_to_timespec(nanos: u64) -> (i64, i32) { ((nanos / ONE_SECOND) as i64, (nanos % ONE_SECOND) as i32) } fn main() { let args: clap::ArgMatches = clap::App::new("utcnow") .author("Jonathan Strong ") .version(clap::crate_version!()) .about("\ncurrent time in utc with non-cryptic interface.\n\n\ for your own safety and well-being, local time functionality is not provided.\n\n\ default output format is rfc3339 with trailing 'Z', e.g. '1999-12-31T23:59:59.999999999Z'") .help_message("help") .version_message("version") .arg(clap::Arg::with_name("unix") .help("display elapsed nanoseconds since 1970-01-01T00:00:00Z") .long("unix") .short("u") .required(false) .takes_value(false)) .arg(clap::Arg::with_name("rfc2822") .help("display in rfc2822 format") .long("rfc2822") .short("r") .required(false) .takes_value(false)) .arg(clap::Arg::with_name("seconds") .help("display unix timestamp in seconds, instead of default nanoseconds") .long("seconds") .short("s") .conflicts_with_all(&["rfc2822", "timespec", "millis"]) .required(false) .takes_value(false)) .arg(clap::Arg::with_name("millis") .help("display unix timestamp in milliseconds, instead of default nanoseconds") .long("millis") .short("m") .conflicts_with_all(&["rfc2822", "timespec", "seconds"]) .required(false) .takes_value(false)) .arg(clap::Arg::with_name("timespec") .help("display as ,") .long("timespec") .short("t") .required(false) .takes_value(false)) .arg(clap::Arg::with_name("null") .short("0") .long("null") .help("terminate displayed time with null character instead of newline") .takes_value(false) .required(false)) .arg(clap::Arg::with_name("unix-to-rfc3339") .long("unix-to-rfc3339") .short("R") .alias("unix-to-utc") .help("convert integer unix timestamp (nanoseconds precision) to datetime \ in rfc3339 format. combine with --seconds or --millis to parse a seconds timestamp with alternate precison") .takes_value(true) .required(false) .conflicts_with_all(&["unix"])) .arg(clap::Arg::with_name("rfc3339-to-unix") .long("rfc3339-to-unix") .short("U") .alias("utc-to-unix") .help("parse rfc3339 timestamp and display it as a unix timestamp") .takes_value(true) .required(false) .conflicts_with_all(&["unix", "unix-to-rfc3339", "rfc2822", "timespec"])) .get_matches(); let (sec, nsec): (i64, i32) = if let Some(ts_str) = args.value_of("unix-to-rfc3339") { // either parse --unix-to-rfc3339 input match u64::from_str(ts_str) { // check alternate precisions --seconds or --millis Ok(seconds) if args.is_present("seconds") => nanos_to_timespec(seconds * ONE_SECOND), Ok(millis) if args.is_present("millis") => nanos_to_timespec(millis * 1_000_000), // otherwise go with default nanos Ok(nanos) => nanos_to_timespec(nanos), Err(e) => { eprintln!("failed to parse timestamp (expected integer): {}", e); std::process::exit(1); } } } else if let Some(rfc_str) = args.value_of("rfc3339-to-unix") { // or --rfc3339-to-unix //match DateTime::::parse_from_rfc3339(rfc_str) { match rfc_str.parse::>() { Ok(utc) => nanos_to_timespec(nanos(utc)), Err(e) => { eprintln!("failed to parse timestamp (expected integer): {}", e); std::process::exit(1); } } } else { // or else get current time get_time() }; let endline = if args.is_present("null") { "\u{0}" } else { "\n" }; // pick endline - \n unless -0 if args.is_present("timespec") { // display timespec print!("{},{}{}", sec, nsec, endline); } else if args.is_present("unix") || args.is_present("rfc3339-to-unix") { // display unix if args.is_present("seconds") { // unix seconds print!("{}{}", sec, endline); } else if args.is_present("millis") { // unix millis print!("{}{}", timespec_to_nanos(sec, nsec) / 1_000_000, endline); } else { // unix nanos print!("{}{}", timespec_to_nanos(sec, nsec), endline); } } else if args.is_present("rfc2822") { // display rfc2822 print!("{}{}", timespec_to_utc(sec, nsec).to_rfc2822(), endline); } else { // display rfc3339 // Debug view is iso format / rfc3339 that we want // Display has spaces - no go // to_rfc3339 uses +00:00 instead of Z, which I don't like print!("{:?}{}", timespec_to_utc(sec, nsec), endline); } }