2026-02-12 23:52:24 +01:00
|
|
|
use crate::calendar::CalendarError;
|
|
|
|
|
|
|
|
|
|
use super::calendar::{create_timetable, get_local_timezone_offset, get_todays_date};
|
|
|
|
|
|
|
|
|
|
use chrono::NaiveDate;
|
|
|
|
|
use chrono::NaiveTime;
|
2026-02-12 21:41:18 +01:00
|
|
|
use clap::Parser;
|
2026-02-12 23:52:24 +01:00
|
|
|
use std::error::Error;
|
|
|
|
|
use std::fmt;
|
|
|
|
|
use std::iter;
|
2026-02-12 21:41:18 +01:00
|
|
|
|
|
|
|
|
#[derive(Parser, Debug)]
|
|
|
|
|
#[command(version, about, long_about = None)]
|
|
|
|
|
pub struct Args {
|
|
|
|
|
#[arg(short, long)]
|
|
|
|
|
pub timezone: Vec<String>,
|
|
|
|
|
|
|
|
|
|
#[arg(short, long)]
|
|
|
|
|
pub date: Option<String>,
|
|
|
|
|
|
2026-02-12 23:52:24 +01:00
|
|
|
#[arg(short, long, default_value = "Local")]
|
|
|
|
|
pub local: String,
|
|
|
|
|
|
2026-02-12 21:41:18 +01:00
|
|
|
pub time: String,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-12 23:52:24 +01:00
|
|
|
#[derive(PartialEq, Debug)]
|
|
|
|
|
pub enum CliError {
|
|
|
|
|
CouldNotParseTime,
|
|
|
|
|
CouldNotParseDate,
|
|
|
|
|
CouldNoGenerateTimetable(CalendarError),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for CliError {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
let message = match *self {
|
|
|
|
|
Self::CouldNotParseTime => "Couldn't parse time".to_string(),
|
|
|
|
|
Self::CouldNotParseDate => "Couldn't parse date".to_string(),
|
|
|
|
|
Self::CouldNoGenerateTimetable(ref er) => {
|
|
|
|
|
format!("Could not generate timetable: {}", er)
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
f.write_str(&message)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Error for CliError {}
|
|
|
|
|
|
|
|
|
|
pub fn print_timezones(
|
|
|
|
|
timezones: &Vec<String>,
|
|
|
|
|
time: &String,
|
|
|
|
|
date: Option<&String>,
|
|
|
|
|
local_timezone: &String,
|
|
|
|
|
) -> Result<(), CliError> {
|
|
|
|
|
let todays_date = &get_todays_date();
|
|
|
|
|
let date = date.unwrap_or(todays_date);
|
|
|
|
|
|
|
|
|
|
let parsed_time = if let Ok(hour) = time.parse::<u32>() {
|
|
|
|
|
NaiveTime::from_hms_opt(hour, 0, 0).ok_or(CliError::CouldNotParseTime)?
|
|
|
|
|
} else {
|
|
|
|
|
NaiveTime::parse_from_str(time, "%H:%M").map_err(|_| CliError::CouldNotParseTime)?
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let parsed_date = NaiveDate::parse_from_str(date, "%d-%m-%Y")
|
|
|
|
|
.or_else(|_| NaiveDate::parse_from_str(date, "%d-%m"))
|
|
|
|
|
.map_err(|_| CliError::CouldNotParseDate)?;
|
|
|
|
|
|
|
|
|
|
let local_timezone_offset = &get_local_timezone_offset(&parsed_time, local_timezone)
|
|
|
|
|
.map_err(|e| CliError::CouldNoGenerateTimetable(e))?;
|
|
|
|
|
|
|
|
|
|
let all_timezones: Vec<&String> = iter::once(&local_timezone_offset.name)
|
|
|
|
|
.chain(timezones)
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
let max_len = all_timezones.iter().map(|t| t.len()).max().unwrap_or(0) as u32;
|
|
|
|
|
|
|
|
|
|
for timezone in all_timezones {
|
2026-02-12 21:41:18 +01:00
|
|
|
let name_padding = (0..(max_len - timezone.len() as u32))
|
|
|
|
|
.map(|_| " ".to_string())
|
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
|
.join("");
|
2026-02-12 23:52:24 +01:00
|
|
|
match create_timetable(
|
|
|
|
|
&parsed_time,
|
|
|
|
|
&parsed_date,
|
|
|
|
|
&local_timezone_offset.offset,
|
|
|
|
|
timezone,
|
|
|
|
|
5,
|
|
|
|
|
) {
|
2026-02-12 21:41:18 +01:00
|
|
|
Ok(timetable) => println!("{}:{}\t{}", timezone, name_padding, timetable.join("\t")),
|
|
|
|
|
Err(error) => panic!("Failed: {}", error),
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-12 23:52:24 +01:00
|
|
|
Ok(())
|
2026-02-12 21:41:18 +01:00
|
|
|
}
|