extern crate chrono; extern crate clap; #[cfg(windows)] extern crate kernel32; #[cfg(not(windows))] extern crate libc; #[cfg(windows)] extern crate winapi; use chrono::DateTime; // date type use chrono::Weekday; use chrono::{Datelike, Timelike}; // traits that provides .year(), .month(), .second() ... methods use chrono::{FixedOffset, Local, NaiveDateTime, Utc}; // timezone types use clap::{App, Arg}; use std::mem::zeroed; use std::thread::sleep; struct Clock; impl Clock { fn get() -> DateTime { Local::now() } #[cfg(windows)] fn set(t: DateTime) -> () { use chrono::Weekday; use kernel32::SetSystemTime; use winapi::{SYSTEMTIME, WORD}; let t = t.with_timezone(&Local); let mut systime: SYSTEMTIME = unsafe { zeroed() }; let dow = match t.weekday() { Weekday::Mon => 1, Weekday::Tue => 2, Weekday::Wed => 3, Weekday::Thu => 4, Weekday::Fri => 5, Weekday::Sat => 6, Weekday::Sun => 0, }; let mut ns = t.nanosecond(); let is_leap_second = ns > 1_000_000_000; if is_leap_second { ns -= 1_000_000_000; } systime.wYear = t.year() as WORD; systime.wMonth = t.month() as WORD; systime.wDayOfWeek = dow as WORD; systime.wDay = t.day() as WORD; systime.wHour = t.hour() as WORD; systime.wMinute = t.minute() as WORD; systime.wSecond = t.second() as WORD; systime.wMilliseconds = (ns / 1_000_000) as WORD; let systime_ptr = &systime as *const SYSTEMTIME; // as *mut SYSTEMTIME; // convert to a pointer, then change its mutability unsafe { SetSystemTime(systime_ptr); // giving a pointer to a value to something outside of Rust's control is unsafe } } #[cfg(not(windows))] fn set(t: DateTime) -> () { use libc::settimeofday; use libc::{suseconds_t, time_t, timeval, timezone}; let t = t.with_timezone(&Local); // variable names indicate the data's progression let mut u: timeval = unsafe { zeroed() }; // through the function u.tv_sec = t.timestamp() as time_t; u.tv_usec = t.timestamp_subsec_micros() as suseconds_t; unsafe { let mock_tz: *const timezone = std::ptr::null(); settimeofday(&u as *const timeval, mock_tz); } } } fn main() { let app = App::new("clock") .version("0.1.2") .about("Gets and (aspirationally) sets the time.") .after_help("Note: UNIX timestamps are parsed as whole seconds since 1st January 1970 0:00:00 UTC. For more accuracy, use another format.") .arg(Arg::with_name("action") .takes_value(true) .possible_values(&["get", "set"]) .default_value("get")) .arg(Arg::with_name("std") .short("s") .long("use-standard") .takes_value(true) .possible_values(&["rfc2822", "rfc3339", "timestamp"]) .default_value("rfc3339")) .arg(Arg::with_name("datetime") .help("When is 'set', apply . Otherwise, ignore.")); let args = app.get_matches(); let action = args.value_of("std").unwrap(); // default_value() has been supplied, let std = args.value_of("std").unwrap(); // so it's safe to use .unwrap() if action == "set" { let t_ = args.value_of("datetime").unwrap(); let parser = match std { "rfc2822" => DateTime::parse_from_rfc2822, "rfc3339" => DateTime::parse_from_rfc3339, //"rfc3339" => |secs:| NaiveDateTime, _ => unimplemented!(), }; let err_msg = format!("Unable to parse {} according to {}", t_, std); let t = parser(t_).expect(&err_msg); Clock::set(t) } let now = Clock::get(); match std { "timestamp" => println!("{}", now.timestamp()), "rfc2822" => println!("{}", now.to_rfc2822()), "rfc3339" => println!("{}", now.to_rfc3339()), _ => unreachable!(), } }