use crate::conversions::{from_unix_ms, to_unix_ms};
use crate::types::{BrightDateError, BrightDateValue};
const MS_PER_DAY: f64 = 86_400_000.0;
pub fn bd_from_local_clock(
reference: BrightDateValue,
hours: u32,
minutes: u32,
seconds: f64,
offset_days: f64,
) -> Result<BrightDateValue, BrightDateError> {
let ref_ms = to_unix_ms(reference);
let offset_ms = offset_days * MS_PER_DAY;
let local_ms = ref_ms + offset_ms;
let local_day_start_ms = (local_ms / MS_PER_DAY).floor() * MS_PER_DAY;
let utc_day_start_ms = local_day_start_ms - offset_ms;
let target_ms = utc_day_start_ms
+ (hours as f64 * 3_600.0 + minutes as f64 * 60.0 + seconds) * 1_000.0;
from_unix_ms(target_ms)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::conversions::from_unix_ms;
fn date_utc_ms(y: i32, m: u32, d: u32, h: u32, mi: u32, s: u32) -> f64 {
use chrono::{TimeZone, Utc};
Utc.with_ymd_and_hms(y, m, d, h, mi, s)
.single()
.unwrap()
.timestamp_millis() as f64
}
#[test]
fn offset_zero_lands_on_requested_utc_clock() {
let bd = bd_from_local_clock(0.0, 14, 30, 0.0, 0.0).unwrap();
let ms = to_unix_ms(bd);
let expected = date_utc_ms(2000, 1, 1, 14, 30, 0);
assert!((ms - expected).abs() < 1.0, "ms {ms} vs {expected}");
}
#[test]
fn pdt_11_lands_on_utc_18_same_date() {
let reference = from_unix_ms(date_utc_ms(2024, 6, 15, 18, 0, 0)).unwrap();
let bd = bd_from_local_clock(reference, 11, 0, 0.0, -7.0 / 24.0).unwrap();
let ms = to_unix_ms(bd);
let expected = date_utc_ms(2024, 6, 15, 18, 0, 0);
assert!((ms - expected).abs() < 1.0);
}
#[test]
fn jst_22_lands_on_utc_13_same_local_day() {
let reference = from_unix_ms(date_utc_ms(2024, 6, 15, 12, 0, 0)).unwrap();
let bd = bd_from_local_clock(reference, 22, 0, 0.0, 9.0 / 24.0).unwrap();
let ms = to_unix_ms(bd);
let expected = date_utc_ms(2024, 6, 15, 13, 0, 0);
assert!((ms - expected).abs() < 1.0);
}
#[test]
fn ist_preserves_half_hour_offset() {
let reference = from_unix_ms(date_utc_ms(2024, 6, 15, 12, 0, 0)).unwrap();
let bd = bd_from_local_clock(reference, 9, 0, 0.0, 5.5 / 24.0).unwrap();
let ms = to_unix_ms(bd);
let expected = date_utc_ms(2024, 6, 15, 3, 30, 0);
assert!((ms - expected).abs() < 1.0);
}
}