Small Rust scripts
1#!/usr/bin/env -S cargo +nightly -Zscript
2
3---
4[package]
5edition = "2024"
6[dependencies]
7argh = "0.1"
8chrono = "0.4"
9---
10
11use argh::FromArgs;
12use chrono::{DateTime, Local, NaiveDateTime, TimeZone, Utc};
13
14#[derive(FromArgs)]
15#[argh(description = "Convert between Unix timestamps and human-readable dates.")]
16struct App {
17 #[argh(switch, description = "use UTC instead of local time.")]
18 utc: bool,
19
20 #[argh(switch, description = "treat timestamp as milliseconds.")]
21 millis: bool,
22
23 #[argh(positional, description = "timestamp, date (YYYY-MM-DD HH:MM:SS), or 'now'.")]
24 input: Option<String>,
25}
26
27fn main() {
28 let app: App = argh::from_env();
29 let input = app.input.as_deref().unwrap_or("now");
30
31 match input {
32 "now" => {
33 let now = Utc::now();
34 if app.millis {
35 println!("{}", now.timestamp_millis());
36 } else {
37 println!("{}", now.timestamp());
38 }
39 }
40 s if s.chars().all(|c| c.is_ascii_digit()) => {
41 let ts: i64 = s.parse().expect("invalid timestamp");
42 let dt = if app.millis {
43 Utc.timestamp_millis_opt(ts).single()
44 } else {
45 Utc.timestamp_opt(ts, 0).single()
46 }
47 .expect("invalid timestamp");
48
49 if app.utc {
50 println!("{}", dt.format("%Y-%m-%d %H:%M:%S UTC"));
51 } else {
52 let local: DateTime<Local> = dt.into();
53 println!("{}", local.format("%Y-%m-%d %H:%M:%S"));
54 }
55 }
56 s => {
57 let naive = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S")
58 .expect("expected format: YYYY-MM-DD HH:MM:SS");
59
60 let dt: DateTime<Utc> = if app.utc {
61 Utc.from_utc_datetime(&naive)
62 } else {
63 Local
64 .from_local_datetime(&naive)
65 .single()
66 .expect("invalid local time")
67 .into()
68 };
69
70 if app.millis {
71 println!("{}", dt.timestamp_millis());
72 } else {
73 println!("{}", dt.timestamp());
74 }
75 }
76 }
77}