use jiff::Timestamp;
use jiff::civil::Date;
use jiff::tz::{Offset, TimeZone};
use crate::{Error, NepaliDate};
const NEPAL_OFFSET_SECONDS: i32 = 5 * 3600 + 45 * 60;
#[cfg_attr(docsrs, doc(cfg(feature = "jiff")))]
impl From<NepaliDate> for Date {
fn from(date: NepaliDate) -> Self {
let ad = date.to_gregorian();
let parts = (
i16::try_from(ad.year()),
i8::try_from(ad.month()),
i8::try_from(ad.day()),
);
match parts {
(Ok(y), Ok(m), Ok(d)) => Date::new(y, m, d).unwrap_or(Date::MIN),
_ => Date::MIN,
}
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "jiff")))]
impl TryFrom<Date> for NepaliDate {
type Error = Error;
fn try_from(date: Date) -> Result<Self, Error> {
let month = u8::try_from(date.month()).map_err(|_| Error::InvalidGregorian)?;
let day = u8::try_from(date.day()).map_err(|_| Error::InvalidGregorian)?;
NepaliDate::from_gregorian(i32::from(date.year()), month, day)
}
}
fn date_at(now: Timestamp, tz: &TimeZone) -> Result<NepaliDate, Error> {
NepaliDate::try_from(tz.to_datetime(now).date())
}
fn nepal() -> TimeZone {
TimeZone::get("Asia/Kathmandu").unwrap_or_else(|_| fixed_nepal())
}
fn fixed_nepal() -> TimeZone {
Offset::from_seconds(NEPAL_OFFSET_SECONDS).map_or(TimeZone::UTC, TimeZone::fixed)
}
#[cfg_attr(docsrs, doc(cfg(feature = "jiff")))]
impl NepaliDate {
#[must_use = "the clock may be out of range"]
pub fn today() -> Result<Self, Error> {
Self::today_in(&nepal())
}
#[must_use = "the clock may be out of range"]
pub fn today_in(tz: &TimeZone) -> Result<Self, Error> {
date_at(Timestamp::now(), tz)
}
#[must_use]
pub fn is_today(self) -> bool {
Self::today() == Ok(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn at(text: &str) -> Timestamp {
text.parse().unwrap_or(Timestamp::UNIX_EPOCH)
}
#[test]
fn clock_at_2024_07_30_18_30_utc() {
let now = at("2024-07-30T18:30:00Z");
let kathmandu = TimeZone::get("Asia/Kathmandu");
assert!(kathmandu.is_ok(), "tzdb has Asia/Kathmandu");
let kathmandu = kathmandu.unwrap_or(TimeZone::UTC);
assert_eq!(date_at(now, &TimeZone::UTC), NepaliDate::new(2081, 4, 15));
assert_eq!(date_at(now, &kathmandu), NepaliDate::new(2081, 4, 16));
assert_eq!(date_at(now, &nepal()), NepaliDate::new(2081, 4, 16));
}
#[test]
fn fixed_offset_fallback_is_nepal_time() {
let fixed = fixed_nepal();
assert_eq!(
date_at(at("2024-07-30T18:15:00Z"), &fixed),
NepaliDate::new(2081, 4, 16)
);
assert_eq!(
date_at(at("2024-07-30T18:14:59Z"), &fixed),
NepaliDate::new(2081, 4, 15)
);
}
#[test]
fn clock_outside_the_supported_range() {
let early = at("1844-04-10T12:00:00Z");
assert_eq!(date_at(early, &TimeZone::UTC), Err(Error::OutOfRange));
let late = at("2143-04-16T12:00:00Z");
assert_eq!(date_at(late, &TimeZone::UTC), Err(Error::OutOfRange));
}
}