const SECONDS_PER_DAY: i64 = 86400;
const UNIX_EPOCH_JDN: i64 = 2440588;
#[allow(clippy::cast_possible_truncation)]
const fn date_to_julian_day(year: i32, month: u32, day: u32) -> Option<i32> {
let a = (14 - month as i32) / 12;
let Some(y) = year.checked_add(4800 - a) else { return None };
let m = month as i32 + 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 as i32) 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)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn now_unix_timestamp() -> i64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs() as i64)
.unwrap_or(0)
}
#[cfg(all(target_arch = "wasm32", feature = "wasm_bindgen"))]
pub fn now_unix_timestamp() -> i64 {
(js_sys::Date::now() / 1000.0) as i64
}
#[cfg(all(target_arch = "wasm32", not(feature = "wasm_bindgen")))]
pub fn now_unix_timestamp() -> 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);
}
}