use local timezone if the local one not set

This commit is contained in:
Ondrej Novak 2026-02-19 21:29:27 +01:00
parent 88ec0a9de2
commit 9394059d5f
3 changed files with 90 additions and 43 deletions

View File

@ -1,19 +1,16 @@
use chrono::{TimeDelta, prelude::*}; use chrono::{TimeDelta, prelude::*};
use chrono_tz::Tz;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub enum CalendarError { pub enum CalendarError {
TimezoneConversionFailed(String), TimezoneConversionFailed,
} }
impl fmt::Display for CalendarError { impl fmt::Display for CalendarError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let message = match *self { let message = match *self {
Self::TimezoneConversionFailed(ref tz) => { Self::TimezoneConversionFailed => "Could not convert time to timezone: {}",
format!("Could not convert time to timezone: {}", tz)
}
}; };
f.write_str(&message) f.write_str(&message)
@ -30,11 +27,11 @@ fn create_timetable_vecs(time: &NaiveTime, padding_hrs: i8) -> Vec<NaiveTime> {
.collect() .collect()
} }
pub fn create_timetable( pub fn create_timetable<TzLocal: TimeZone, TzTarget: TimeZone>(
target_time: &NaiveTime, target_time: &NaiveTime,
target_date: &NaiveDate, target_date: &NaiveDate,
local_timezone: &Tz, local_timezone: &TzLocal,
target_timezone: &Tz, target_timezone: &TzTarget,
padding_hrs: i8, padding_hrs: i8,
) -> Result<Vec<NaiveTime>, CalendarError> { ) -> Result<Vec<NaiveTime>, CalendarError> {
let datetime = local_timezone let datetime = local_timezone
@ -43,9 +40,7 @@ pub fn create_timetable(
target_time.clone(), target_time.clone(),
)) ))
.single() .single()
.ok_or_else(|| { .ok_or_else(|| CalendarError::TimezoneConversionFailed)?;
CalendarError::TimezoneConversionFailed(local_timezone.name().to_string())
})?;
let time_in_timezone = datetime.with_timezone(target_timezone); let time_in_timezone = datetime.with_timezone(target_timezone);
Ok(create_timetable_vecs(&time_in_timezone.time(), padding_hrs)) Ok(create_timetable_vecs(&time_in_timezone.time(), padding_hrs))

View File

@ -1,8 +1,9 @@
use super::calendar::{create_timetable, get_todays_date}; use super::calendar::{create_timetable, get_todays_date};
use chrono::Local;
use chrono::NaiveDate; use chrono::NaiveDate;
use chrono::NaiveTime; use chrono::NaiveTime;
use chrono_tz::Etc::UTC; use chrono::TimeZone;
use chrono_tz::Tz; use chrono_tz::Tz;
use clap::Parser; use clap::Parser;
use colored::Colorize; use colored::Colorize;
@ -30,7 +31,7 @@ pub enum CliError {
CouldNotParseTime, CouldNotParseTime,
CouldNotParseDate, CouldNotParseDate,
CouldNotParseTimezone(String), CouldNotParseTimezone(String),
CouldNoGenerateTimetable(String), CouldNotGenerateTimetable(String),
} }
impl fmt::Display for CliError { impl fmt::Display for CliError {
@ -41,7 +42,7 @@ impl fmt::Display for CliError {
Self::CouldNotParseTimezone(ref tz) => { Self::CouldNotParseTimezone(ref tz) => {
format!("Couldn't parse timezone {}", tz).to_string() format!("Couldn't parse timezone {}", tz).to_string()
} }
Self::CouldNoGenerateTimetable(ref er) => { Self::CouldNotGenerateTimetable(ref er) => {
format!("Could not generate timetable: {}", er) format!("Could not generate timetable: {}", er)
} }
}; };
@ -52,11 +53,17 @@ impl fmt::Display for CliError {
impl Error for CliError {} impl Error for CliError {}
// struct Timetable {
// pub name: String,
// pub values: Vec<NaiveTime>,
// }
pub fn print_timezones( pub fn print_timezones(
timezones: &Vec<String>, timezones: &Vec<String>,
time: &String, time: &String,
date: Option<&String>, date: Option<&String>,
local_timezone: &String, local_timezone: &String,
padding_hours: i8,
) -> Result<(), CliError> { ) -> Result<(), CliError> {
let todays_date = &get_todays_date(); let todays_date = &get_todays_date();
let date = date.unwrap_or(todays_date); let date = date.unwrap_or(todays_date);
@ -71,13 +78,52 @@ pub fn print_timezones(
.or_else(|_| NaiveDate::parse_from_str(date, "%d-%m")) .or_else(|_| NaiveDate::parse_from_str(date, "%d-%m"))
.map_err(|_| CliError::CouldNotParseDate)?; .map_err(|_| CliError::CouldNotParseDate)?;
let parsed_local_timezone: Tz = if local_timezone == "Local" { if local_timezone == "Local" {
UTC // FIXME: use local timezone instead print_calendar(
parsed_time,
parsed_date,
Local,
&"Local".to_string(),
&timezones,
padding_hours,
)
} else { } else {
local_timezone let timezone = local_timezone
.parse::<Tz>() .parse::<Tz>()
.map_err(|_| CliError::CouldNoGenerateTimetable(local_timezone.to_string()))? .map_err(|_| CliError::CouldNotGenerateTimetable(local_timezone.to_string()))?;
}; print_calendar(
parsed_time,
parsed_date,
timezone,
&timezone.name().to_string(),
&timezones,
padding_hours,
)
}
}
fn print_calendar<TzLocal: TimeZone>(
parsed_time: NaiveTime,
parsed_date: NaiveDate,
parsed_local_timezone: TzLocal,
local_timezone_name: &String,
timezones: &Vec<String>,
padding_hours: i8,
) -> Result<(), CliError> {
let local_timetable = create_timetable(
&parsed_time,
&parsed_date,
&parsed_local_timezone,
&parsed_local_timezone,
padding_hours,
)
.map_err(|_| CliError::CouldNotParseTimezone(local_timezone_name.to_string()))?;
let longest_name_length = iter::once(local_timezone_name.to_string())
.chain(timezones.iter().map(|tz| tz.to_string()))
.map(|t| t.len())
.max()
.unwrap_or(0) as u32;
let parsed_timezones: Vec<Tz> = timezones let parsed_timezones: Vec<Tz> = timezones
.iter() .iter()
@ -87,31 +133,31 @@ pub fn print_timezones(
}) })
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let all_timezones: Vec<Tz> = iter::once(parsed_local_timezone) let target_timetables = parsed_timezones
.chain(parsed_timezones)
.collect();
let max_len = all_timezones
.iter() .iter()
.map(|t| t.name().len()) .map(|tz| {
.max() create_timetable(
.unwrap_or(0) as u32; &parsed_time,
&parsed_date,
&parsed_local_timezone,
tz,
padding_hours,
)
.map(|tt| (tz.name().to_string(), tt))
.map_err(|_| CliError::CouldNotGenerateTimetable(tz.name().to_string()))
})
.collect::<Result<Vec<_>, _>>()?;
for timezone in all_timezones { let all_timetables: Vec<(String, Vec<NaiveTime>)> =
let timezone_name = timezone.name(); iter::once((local_timezone_name.to_string(), local_timetable))
let name_padding_len = max_len - timezone_name.len() as u32; .chain(target_timetables)
match create_timetable( .collect();
&parsed_time,
&parsed_date, for timezone in all_timetables {
&parsed_local_timezone, let name: String = timezone.0;
&timezone, let timetable = timezone.1;
5, let name_padding_len = longest_name_length - name.len() as u32;
) { print_timetable(&name, name_padding_len, &timetable)
Ok(timetable) => {
print_timetable(&timezone_name.to_string(), name_padding_len, &timetable)
}
Err(error) => panic!("Failed: {}", error),
}
} }
Ok(()) Ok(())
} }

View File

@ -8,7 +8,13 @@ fn main() {
let args = Args::parse(); let args = Args::parse();
if args.timezone.len() > 0 { if args.timezone.len() > 0 {
let res = print_timezones(&args.timezone, &args.time, args.date.as_ref(), &args.local); let res = print_timezones(
&args.timezone,
&args.time,
args.date.as_ref(),
&args.local,
5,
);
if let Err(error) = res { if let Err(error) = res {
println!("Error: {}", error); println!("Error: {}", error);