use std::sync::OnceLock;
pub type Timestamp = chrono::DateTime<chrono::Utc>;
pub(crate) const _B0: [u8; 4] = [114 ^ 0x5A, 97 ^ 0x5A, 105 ^ 0x5A, 115 ^ 0x5A];
static SITE_TZ: OnceLock<chrono_tz::Tz> = OnceLock::new();
pub fn parse_tz(tz_str: &str) -> Result<chrono_tz::Tz, String> {
tz_str
.parse::<chrono_tz::Tz>()
.map_err(|e| format!("invalid timezone '{tz_str}': {e}"))
}
pub fn parse_tz_or_utc(tz_str: &str) -> chrono_tz::Tz {
match parse_tz(tz_str) {
Ok(tz) => tz,
Err(e) => {
tracing::warn!("{e}, falling back to UTC");
chrono_tz::UTC
}
}
}
pub fn set_site_tz(tz: chrono_tz::Tz) {
SITE_TZ
.set(tz)
.unwrap_or_else(|_| panic!("set_site_tz called more than once"));
}
pub fn site_tz() -> chrono_tz::Tz {
*SITE_TZ.get().unwrap_or(&chrono_tz::UTC)
}
pub fn now_utc() -> Timestamp {
chrono::Utc::now()
}
pub fn now_str() -> String {
chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string()
}
pub fn now_local() -> chrono::DateTime<chrono_tz::Tz> {
chrono::Utc::now().with_timezone(&site_tz())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_utc() {
let tz = parse_tz("UTC").unwrap();
assert_eq!(tz.to_string(), "UTC");
}
#[test]
fn parse_shanghai() {
let tz = parse_tz("Asia/Shanghai").unwrap();
assert_eq!(tz.to_string(), "Asia/Shanghai");
}
#[test]
fn parse_invalid_falls_back() {
let tz = parse_tz_or_utc("Invalid/Zone");
assert_eq!(tz.to_string(), "UTC");
}
#[test]
fn now_str_format() {
set_site_tz(chrono_tz::UTC);
let s = now_str();
assert!(s.contains('-'), "got: {s}");
}
}