refactor: testing, modules, hour only
Signed-off-by: Christina Sørensen <christina@cafkafk.com>
This commit is contained in:
parent
863ab051e5
commit
0d13db11be
2 changed files with 234 additions and 42 deletions
|
@ -27,6 +27,11 @@
|
||||||
|
|
||||||
cargoHash = "sha256-9sA6eHkJAFB4PRX7SG5RQXAGi5RRd8m3cPien/H/1fU=";
|
cargoHash = "sha256-9sA6eHkJAFB4PRX7SG5RQXAGi5RRd8m3cPien/H/1fU=";
|
||||||
|
|
||||||
|
cargoCheckFlags = ["--show-output"];
|
||||||
|
|
||||||
|
TZ = "CET";
|
||||||
|
RUST_BACKTRACE = 1;
|
||||||
|
|
||||||
src = ./.;
|
src = ./.;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
241
src/main.rs
241
src/main.rs
|
@ -1,45 +1,64 @@
|
||||||
/// GPLv3 2024 KLM banana bread©
|
/// GPLv3 2024 KLM banana bread©
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use std::{env, io};
|
use std::{env, io};
|
||||||
|
use utils::print_time_delta;
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
use crate::utils::parse_timestamp;
|
||||||
let args: Vec<String> = env::args().collect();
|
|
||||||
|
|
||||||
if args.len() == 1
|
#[derive(Debug)]
|
||||||
|| !(args[1].len() == 8 as usize
|
struct SharedState {
|
||||||
|| args[1].len() == 19 as usize
|
now: DateTime<Local>,
|
||||||
|| args[1].len() >= 21 as usize)
|
tz: FixedOffset,
|
||||||
{
|
|
||||||
println!("usage: since hh:mm:ss"); //8
|
|
||||||
println!("usage: since yyyy-mm-dd hh:mm:ss"); //19
|
|
||||||
println!("usage: since <RFC 3339 timestamp>"); //21
|
|
||||||
std::process::abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = &args[1];
|
impl SharedState {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
now: Local::now(),
|
||||||
|
tz: *Local::now().offset(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let tz = *Local::now().offset();
|
fn new_from(now: DateTime<Local>, tz: FixedOffset) -> Self {
|
||||||
|
Self { now, tz }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let timestamp: DateTime<Local>;
|
mod utils {
|
||||||
if let Some(t) = buffer.parse::<DateTime<Local>>().ok() {
|
use chrono::{prelude::*, TimeDelta};
|
||||||
timestamp = t;
|
|
||||||
} else if let Some(t) = NaiveDateTime::parse_from_str(buffer, "%Y-%m-%d %H:%M:%S").ok() {
|
use crate::SharedState;
|
||||||
timestamp = t.and_local_timezone(tz).single().unwrap().into();
|
|
||||||
} else if let Some(t) = NaiveTime::parse_from_str(buffer, "%H:%M:%S").ok() {
|
#[inline]
|
||||||
timestamp = NaiveDateTime::new(Local::now().date_naive(), t)
|
pub fn naive_time_to_local_datetime(ctx: &SharedState, t: NaiveTime) -> DateTime<Local> {
|
||||||
.and_local_timezone(tz)
|
NaiveDateTime::new(ctx.now.date_naive(), t)
|
||||||
|
.and_local_timezone(ctx.tz)
|
||||||
.single()
|
.single()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into();
|
.into()
|
||||||
} else {
|
|
||||||
println!("Couldn't parse timestamp!");
|
|
||||||
std::process::abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let now = Local::now();
|
#[inline]
|
||||||
|
pub fn parse_timestamp(ctx: &SharedState, input: &String) -> DateTime<Local> {
|
||||||
|
let tz = ctx.tz;
|
||||||
|
|
||||||
let delta = DateTime::signed_duration_since(now, timestamp);
|
if let Some(t) = input.parse::<DateTime<Local>>().ok() {
|
||||||
|
t
|
||||||
|
} else if let Some(t) = NaiveDateTime::parse_from_str(input, "%Y-%m-%d %H:%M:%S").ok() {
|
||||||
|
t.and_local_timezone(tz).single().unwrap().into()
|
||||||
|
} else if let Some(t) = NaiveTime::parse_from_str(&[&input, ":00"].concat(), "%H:%M").ok() {
|
||||||
|
naive_time_to_local_datetime(ctx, t)
|
||||||
|
} else if let Some(t) = NaiveTime::parse_from_str(input, "%H:%M").ok() {
|
||||||
|
naive_time_to_local_datetime(ctx, t)
|
||||||
|
} else if let Some(t) = NaiveTime::parse_from_str(input, "%H:%M:%S").ok() {
|
||||||
|
naive_time_to_local_datetime(ctx, t)
|
||||||
|
} else {
|
||||||
|
panic!("Couldn't parse timestamp.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn print_time_delta(delta: TimeDelta) {
|
||||||
let days = ((delta.num_seconds() / 60) / 60) / 24;
|
let days = ((delta.num_seconds() / 60) / 60) / 24;
|
||||||
let hours = ((delta.num_seconds() / 60) / 60) % 24;
|
let hours = ((delta.num_seconds() / 60) / 60) % 24;
|
||||||
let minutes = (delta.num_seconds() / 60) % 60;
|
let minutes = (delta.num_seconds() / 60) % 60;
|
||||||
|
@ -49,5 +68,173 @@ fn main() -> io::Result<()> {
|
||||||
"{}d {}h {:0>2}m {:0>2}s",
|
"{}d {}h {:0>2}m {:0>2}s",
|
||||||
days, &hours, minutes as f32, seconds
|
days, &hours, minutes as f32, seconds
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const DATE: &str = "1998-01-20T16:00:00+01:00";
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_ctx() -> SharedState {
|
||||||
|
let test_date = DATE.parse::<DateTime<Local>>().unwrap();
|
||||||
|
dbg!(test_date);
|
||||||
|
SharedState::new_from(test_date, *test_date.offset())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_timestamp_h() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"10".to_string()),
|
||||||
|
"1998-01-20T10:00:00+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Couldn't parse timestamp.")]
|
||||||
|
fn parse_timestamp_h_high() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"24".to_string()),
|
||||||
|
"1998-01-20T10:00:00+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_timestamp_hm() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"23:59".to_string()),
|
||||||
|
"1998-01-20T23:59:00+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Couldn't parse timestamp.")]
|
||||||
|
fn parse_timestamp_hm_highh() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"24:59".to_string()),
|
||||||
|
"1998-01-20T23:59:00+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Couldn't parse timestamp.")]
|
||||||
|
fn parse_timestamp_hm_highm() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"23:60".to_string()),
|
||||||
|
"1998-01-20T23:59:00+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Couldn't parse timestamp.")]
|
||||||
|
fn parse_timestamp_hm_highhm() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"24:60".to_string()),
|
||||||
|
"1998-01-20T23:59:00+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_timestamp_hms() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"23:59:59".to_string()),
|
||||||
|
"1998-01-20T23:59:59+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Couldn't parse timestamp.")]
|
||||||
|
fn parse_timestamp_hms_highh() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"24:59:59".to_string()),
|
||||||
|
"1998-01-20T24:59:59+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Couldn't parse timestamp.")]
|
||||||
|
fn parse_timestamp_hms_highm() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"23:60:59".to_string()),
|
||||||
|
"1998-01-20T23:60:59+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Couldn't parse timestamp.")]
|
||||||
|
fn parse_timestamp_hms_highs() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"23:59:61".to_string()),
|
||||||
|
"1998-01-20T23:59:61+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "Couldn't parse timestamp.")]
|
||||||
|
fn parse_timestamp_hms_highhms() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"24:60:61".to_string()),
|
||||||
|
"1998-01-20T24:60:61+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_timestamp_default() {
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"1998-01-20T23:59:59+01:00".to_string()),
|
||||||
|
"1998-01-20T23:59:59+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_timestamp(&get_ctx(), &"1998-01-20T23:59:59Z".to_string()),
|
||||||
|
"1998-01-21T00:59:59+01:00"
|
||||||
|
.parse::<DateTime<Local>>()
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
// FIXME
|
||||||
|
// assert_eq!(
|
||||||
|
// parse_timestamp(&get_ctx(), &"1998-01-20T23:59:59Z+02:00".to_string()),
|
||||||
|
// "1998-01-21T23:59:59+01:00"
|
||||||
|
// .parse::<DateTime<Local>>()
|
||||||
|
// .unwrap()
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
|
let ctx = SharedState::new();
|
||||||
|
|
||||||
|
print_time_delta(DateTime::signed_duration_since(
|
||||||
|
ctx.now,
|
||||||
|
parse_timestamp(&ctx, &args[1]),
|
||||||
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue