const SECONDS_PER_DAY: i64 = 86400;
const UNIX_EPOCH_JDN: i64 = 2440588;
const fn date_to_julian_day(year: i32, month: u32, day: u32) -> Option<i32> {
let a = (14 - month.cast_signed()) / 12;
let Some(y) = year.checked_add(4800 - a) else { return None };
let m = month.cast_signed() + 12 * a - 3;
let Some(term1) = 365_i32.checked_mul(y) else { return None };
let Some(term2) = term1.checked_add((153 * m + 2) / 5) else { return None };
let Some(term3) = term2.checked_add(day.cast_signed()) else { return None };
let Some(term4) = term3.checked_add(y / 4) else { return None };
let Some(term5) = term4.checked_sub(y / 100) else { return None };
let Some(term6) = term5.checked_add(y / 400) else { return None };
term6.checked_sub(32045)
}
pub fn date_to_unix_timestamp(year: i32, month: u32, day: u32) -> Option<i64> {
if !(1..=12).contains(&month) || !(1..=31).contains(&day) {
return None;
}
let jdn = i64::from(date_to_julian_day(year, month, day)?);
Some((jdn - UNIX_EPOCH_JDN) * SECONDS_PER_DAY)
}
pub fn now_unix_timestamp() -> i64 {
std::cfg_select! {
not(target_arch = "wasm32") => {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs().cast_signed())
.unwrap_or(0)
}
feature = "wasm_bindgen" => {
(js_sys::Date::now() / 1000.0) as i64
}
_ => {
0
}
}
}
pub fn now_julian_day() -> i32 {
let ts = now_unix_timestamp();
((ts / SECONDS_PER_DAY) + UNIX_EPOCH_JDN) as i32
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_date_to_julian_day() {
assert_eq!(date_to_julian_day(2000, 1, 1), Some(2451545)); assert_eq!(date_to_julian_day(1970, 1, 1), Some(2440588)); assert_eq!(date_to_julian_day(i32::MAX, 1, 1), None);
}
#[test]
fn test_date_to_unix_timestamp() {
assert_eq!(date_to_unix_timestamp(1970, 1, 1), Some(0));
assert_eq!(date_to_unix_timestamp(2000, 1, 1), Some(946684800));
assert_eq!(date_to_unix_timestamp(2000, 0, 1), None);
assert_eq!(date_to_unix_timestamp(2000, 13, 1), None);
assert_eq!(date_to_unix_timestamp(2000, 1, 0), None);
assert_eq!(date_to_unix_timestamp(2000, 1, 32), None);
}
}