tzhelp/src/calendar.rs

159 lines
5.1 KiB
Rust
Raw Normal View History

use chrono::{TimeDelta, prelude::*};
use chrono_tz::Tz;
use std::error::Error;
use std::fmt;
#[derive(PartialEq, Debug)]
2026-02-12 21:41:18 +01:00
pub enum CalendarError {
TimezoneConversionFailed(String),
}
impl fmt::Display for CalendarError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let message = match *self {
Self::TimezoneConversionFailed(ref tz) => {
format!("Could not convert time to timezone: {}", tz)
}
};
f.write_str(&message)
}
}
impl Error for CalendarError {}
2026-02-17 23:42:26 +01:00
fn create_timetable_vecs(time: &NaiveTime, padding_hrs: i8) -> Vec<NaiveTime> {
let start = -padding_hrs;
let end = padding_hrs;
(start..=end)
.map(|v| time.overflowing_add_signed(TimeDelta::hours(v.into())).0)
.collect()
}
pub fn create_timetable(
target_time: &NaiveTime,
target_date: &NaiveDate,
2026-02-17 23:42:26 +01:00
local_timezone: &Tz,
target_timezone: &Tz,
padding_hrs: i8,
2026-02-17 23:42:26 +01:00
) -> Result<Vec<NaiveTime>, CalendarError> {
let datetime = local_timezone
.from_local_datetime(&NaiveDateTime::new(
target_date.clone(),
target_time.clone(),
))
.single()
.ok_or_else(|| {
CalendarError::TimezoneConversionFailed(local_timezone.name().to_string())
})?;
let time_in_timezone = datetime.with_timezone(target_timezone);
Ok(create_timetable_vecs(&time_in_timezone.time(), padding_hrs))
}
2026-02-12 21:41:18 +01:00
pub fn get_todays_date() -> String {
Local::now().format("%d-%m-%Y").to_string()
}
#[cfg(test)]
mod tests {
use super::*;
2026-02-17 23:42:26 +01:00
use chrono_tz::Europe::Prague;
#[test]
2026-02-17 23:42:26 +01:00
fn test_timetable_vecs() {
assert_eq!(
2026-02-17 23:42:26 +01:00
create_timetable_vecs(&NaiveTime::from_hms_opt(10, 0, 0).unwrap(), 4),
vec![
2026-02-17 23:42:26 +01:00
NaiveTime::from_hms_opt(06, 0, 0).unwrap(),
NaiveTime::from_hms_opt(07, 0, 0).unwrap(),
NaiveTime::from_hms_opt(08, 0, 0).unwrap(),
NaiveTime::from_hms_opt(09, 0, 0).unwrap(),
NaiveTime::from_hms_opt(10, 0, 0).unwrap(),
NaiveTime::from_hms_opt(11, 0, 0).unwrap(),
NaiveTime::from_hms_opt(12, 0, 0).unwrap(),
NaiveTime::from_hms_opt(13, 0, 0).unwrap(),
NaiveTime::from_hms_opt(14, 0, 0).unwrap(),
]
);
}
#[test]
2026-02-17 23:42:26 +01:00
fn test_timetable_vecs_overflow() {
assert_eq!(
2026-02-17 23:42:26 +01:00
create_timetable_vecs(&NaiveTime::from_hms_opt(3, 0, 0).unwrap(), 4),
vec![
2026-02-17 23:42:26 +01:00
NaiveTime::from_hms_opt(23, 0, 0).unwrap(),
NaiveTime::from_hms_opt(00, 0, 0).unwrap(),
NaiveTime::from_hms_opt(01, 0, 0).unwrap(),
NaiveTime::from_hms_opt(02, 0, 0).unwrap(),
NaiveTime::from_hms_opt(03, 0, 0).unwrap(),
NaiveTime::from_hms_opt(04, 0, 0).unwrap(),
NaiveTime::from_hms_opt(05, 0, 0).unwrap(),
NaiveTime::from_hms_opt(06, 0, 0).unwrap(),
NaiveTime::from_hms_opt(07, 0, 0).unwrap(),
]
);
}
#[test]
2026-02-17 23:42:26 +01:00
fn test_timetable_vecs_underflow() {
assert_eq!(
2026-02-17 23:42:26 +01:00
create_timetable_vecs(&NaiveTime::from_hms_opt(22, 0, 0).unwrap(), 4),
vec![
2026-02-17 23:42:26 +01:00
NaiveTime::from_hms_opt(18, 0, 0).unwrap(),
NaiveTime::from_hms_opt(19, 0, 0).unwrap(),
NaiveTime::from_hms_opt(20, 0, 0).unwrap(),
NaiveTime::from_hms_opt(21, 0, 0).unwrap(),
NaiveTime::from_hms_opt(22, 0, 0).unwrap(),
NaiveTime::from_hms_opt(23, 0, 0).unwrap(),
NaiveTime::from_hms_opt(00, 0, 0).unwrap(),
NaiveTime::from_hms_opt(01, 0, 0).unwrap(),
NaiveTime::from_hms_opt(02, 0, 0).unwrap(),
]
);
}
#[test]
fn test_create_timezone() {
assert_eq!(
create_timetable(
2026-02-17 23:42:26 +01:00
&NaiveTime::from_hms_opt(10, 0, 0).unwrap(),
&NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(),
&Prague,
&Prague,
2
)
.unwrap(),
2026-02-17 23:42:26 +01:00
vec![
NaiveTime::from_hms_opt(08, 0, 0).unwrap(),
NaiveTime::from_hms_opt(09, 0, 0).unwrap(),
NaiveTime::from_hms_opt(10, 0, 0).unwrap(),
NaiveTime::from_hms_opt(11, 0, 0).unwrap(),
NaiveTime::from_hms_opt(12, 0, 0).unwrap()
]
);
}
#[test]
fn test_create_timezone_nonzero_minutes() {
assert_eq!(
create_timetable(
2026-02-17 23:42:26 +01:00
&NaiveTime::from_hms_opt(10, 30, 0).unwrap(),
&NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(),
&Prague,
&Prague,
2
)
.unwrap(),
2026-02-17 23:42:26 +01:00
vec![
NaiveTime::from_hms_opt(08, 30, 0).unwrap(),
NaiveTime::from_hms_opt(09, 30, 0).unwrap(),
NaiveTime::from_hms_opt(10, 30, 0).unwrap(),
NaiveTime::from_hms_opt(11, 30, 0).unwrap(),
NaiveTime::from_hms_opt(12, 30, 0).unwrap()
]
);
}
}