150 lines
4.9 KiB
Rust
150 lines
4.9 KiB
Rust
use chrono::{TimeDelta, prelude::*};
|
|
use std::error::Error;
|
|
use std::fmt;
|
|
|
|
#[derive(PartialEq, Debug)]
|
|
pub enum CalendarError {
|
|
TimezoneConversionFailed,
|
|
}
|
|
|
|
impl fmt::Display for CalendarError {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let message = match *self {
|
|
Self::TimezoneConversionFailed => "Could not convert time to timezone: {}",
|
|
};
|
|
|
|
f.write_str(&message)
|
|
}
|
|
}
|
|
|
|
impl Error for CalendarError {}
|
|
|
|
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<TzLocal: TimeZone, TzTarget: TimeZone>(
|
|
target_time: &NaiveTime,
|
|
target_date: &NaiveDate,
|
|
local_timezone: &TzLocal,
|
|
target_timezone: &TzTarget,
|
|
padding_hrs: i8,
|
|
) -> 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)?;
|
|
let time_in_timezone = datetime.with_timezone(target_timezone);
|
|
|
|
Ok(create_timetable_vecs(&time_in_timezone.time(), padding_hrs))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use chrono_tz::Europe::Prague;
|
|
|
|
#[test]
|
|
fn test_timetable_vecs() {
|
|
assert_eq!(
|
|
create_timetable_vecs(&NaiveTime::from_hms_opt(10, 0, 0).unwrap(), 4),
|
|
vec![
|
|
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]
|
|
fn test_timetable_vecs_overflow() {
|
|
assert_eq!(
|
|
create_timetable_vecs(&NaiveTime::from_hms_opt(3, 0, 0).unwrap(), 4),
|
|
vec![
|
|
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]
|
|
fn test_timetable_vecs_underflow() {
|
|
assert_eq!(
|
|
create_timetable_vecs(&NaiveTime::from_hms_opt(22, 0, 0).unwrap(), 4),
|
|
vec![
|
|
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(
|
|
&NaiveTime::from_hms_opt(10, 0, 0).unwrap(),
|
|
&NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(),
|
|
&Prague,
|
|
&Prague,
|
|
2
|
|
)
|
|
.unwrap(),
|
|
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(
|
|
&NaiveTime::from_hms_opt(10, 30, 0).unwrap(),
|
|
&NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(),
|
|
&Prague,
|
|
&Prague,
|
|
2
|
|
)
|
|
.unwrap(),
|
|
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()
|
|
]
|
|
);
|
|
}
|
|
}
|