|
- #![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<Utc>) -> 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<Utc> {
- 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 <jonathan.strong@gmail.com>")
- .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 <sec>,<nsec>")
- .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::<Utc>::parse_from_rfc3339(rfc_str) {
- match rfc_str.parse::<DateTime<Utc>>() {
- 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);
- }
- }
|