use crate::types::BrightDateValue;
pub const TIMEZONE_OFFSETS: &[(&str, f64)] = &[
("UTC-12", -12.0 / 24.0),
("UTC-11", -11.0 / 24.0),
("UTC-10", -10.0 / 24.0), ("UTC-9", -9.0 / 24.0), ("UTC-8", -8.0 / 24.0), ("UTC-7", -7.0 / 24.0), ("UTC-6", -6.0 / 24.0), ("UTC-5", -5.0 / 24.0), ("UTC-4", -4.0 / 24.0), ("UTC-3", -3.0 / 24.0), ("UTC-2", -2.0 / 24.0),
("UTC-1", -1.0 / 24.0),
("UTC+0", 0.0), ("UTC+1", 1.0 / 24.0), ("UTC+2", 2.0 / 24.0), ("UTC+3", 3.0 / 24.0), ("UTC+4", 4.0 / 24.0), ("UTC+5", 5.0 / 24.0), ("UTC+5.5", 5.5 / 24.0), ("UTC+5.75", 5.75 / 24.0), ("UTC+6", 6.0 / 24.0), ("UTC+6.5", 6.5 / 24.0), ("UTC+7", 7.0 / 24.0), ("UTC+8", 8.0 / 24.0), ("UTC+9", 9.0 / 24.0), ("UTC+9.5", 9.5 / 24.0), ("UTC+10", 10.0 / 24.0), ("UTC+11", 11.0 / 24.0),
("UTC+12", 12.0 / 24.0), ("UTC+13", 13.0 / 24.0), ("UTC+14", 14.0 / 24.0), ];
pub fn to_local_value(bright_date: BrightDateValue, offset_days: f64) -> BrightDateValue {
bright_date + offset_days
}
pub fn from_local_value(local_value: BrightDateValue, offset_days: f64) -> BrightDateValue {
local_value - offset_days
}
pub fn get_timezone_offset(timezone: &str) -> Option<f64> {
TIMEZONE_OFFSETS
.iter()
.find(|(name, _)| *name == timezone)
.map(|(_, offset)| *offset)
}
pub fn hours_to_fractional_days(hours: f64) -> f64 {
hours / 24.0
}
pub fn fractional_days_to_hours(fractional_days: f64) -> f64 {
fractional_days * 24.0
}
pub fn format_with_timezone(bright_date: BrightDateValue, timezone: &str, precision: usize) -> String {
match get_timezone_offset(timezone) {
None => format!(
"{:.prec$} (unknown timezone: {timezone})",
bright_date,
prec = precision
),
Some(offset) => {
let local = to_local_value(bright_date, offset);
format!(
"{:.prec$} ({timezone}: {:.prec$})",
bright_date,
local,
prec = precision
)
}
}
}
pub fn local_time_of_day(bright_date: BrightDateValue, offset_days: f64) -> f64 {
let local = bright_date + offset_days;
let frac = local - local.floor();
((frac % 1.0) + 1.0) % 1.0
}
pub fn is_daytime(bright_date: BrightDateValue, offset_days: f64) -> bool {
let tod = local_time_of_day(bright_date, offset_days);
(6.0 / 24.0..18.0 / 24.0).contains(&tod)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn utc_offset_zero() {
assert_eq!(get_timezone_offset("UTC+0"), Some(0.0));
}
#[test]
fn local_value_roundtrip() {
let bd = 9622.5;
let offset = -5.0 / 24.0;
let local = to_local_value(bd, offset);
let back = from_local_value(local, offset);
assert!((back - bd).abs() < 1e-12);
}
#[test]
fn hours_conversion_roundtrip() {
let h = 5.5_f64;
assert!((fractional_days_to_hours(hours_to_fractional_days(h)) - h).abs() < 1e-12);
}
#[test]
fn daytime_detection() {
let noon = 0.0 + 12.0 / 24.0; assert!(is_daytime(100.5, 0.0));
assert!(!is_daytime(100.0 + 2.0 / 24.0, 0.0));
let _ = noon; }
}