use crate::Offset;
use core::convert::TryFrom;
impl TryFrom<crate::Time> for jiff::civil::Time {
type Error = jiff::Error;
fn try_from(t: crate::Time) -> Result<Self, Self::Error> {
jiff::civil::Time::new(
t.hour.try_into().unwrap(),
t.minute.try_into().unwrap(),
t.second.try_into().unwrap(),
t.millisecond.try_into().unwrap(),
)
}
}
impl crate::Time {
pub fn into_civil_time(self) -> Option<jiff::civil::Time> {
jiff::civil::Time::try_from(self).ok()
}
pub fn jiff_fixed_tz(o: Option<crate::Offset>) -> Result<jiff::tz::TimeZone, jiff::Error> {
let o_seconds = if let Some(o) = o {
match o {
Offset::Fixed {
hours,
minutes,
critical: _,
} => hours * 3600 + minutes * 60,
Offset::LocalUnknown { critical: _ } => 0,
}
} else {
0
};
Ok(jiff::tz::TimeZone::fixed(jiff::tz::Offset::from_seconds(
o_seconds.try_into().unwrap(),
)?))
}
}
impl TryFrom<crate::Date> for jiff::civil::Date {
type Error = jiff::Error;
fn try_from(d: crate::Date) -> Result<Self, Self::Error> {
match d {
crate::Date::YMD { year, month, day } => {
jiff::civil::Date::new(year as i16, month as i8, day.try_into().unwrap())
}
crate::Date::Week { year, week, day } => {
let wd = match day {
1 => jiff::civil::Weekday::Monday,
2 => jiff::civil::Weekday::Tuesday,
3 => jiff::civil::Weekday::Wednesday,
4 => jiff::civil::Weekday::Thursday,
5 => jiff::civil::Weekday::Friday,
6 => jiff::civil::Weekday::Saturday,
7 => jiff::civil::Weekday::Sunday,
_ => panic!("Invalid day of week"),
};
Ok(jiff::civil::ISOWeekDate::new(
year.try_into().unwrap(),
week.try_into().unwrap(),
wd,
)?
.into())
}
crate::Date::Ordinal { year, day } => {
jiff::civil::Date::new(year.try_into().unwrap(), 1, 1)?
.with()
.day_of_year(day.try_into().unwrap())
.build()
}
}
}
}
impl crate::Date {
pub fn into_civil_date(self) -> Option<jiff::civil::Date> {
jiff::civil::Date::try_from(self).ok()
}
}
impl TryFrom<crate::DateTime> for jiff::civil::DateTime {
type Error = jiff::Error;
fn try_from(dt: crate::DateTime) -> Result<Self, Self::Error> {
let naive_date = jiff::civil::Date::try_from(dt.date)?;
let naive_time = jiff::civil::Time::try_from(dt.time)?;
Ok(naive_date.to_datetime(naive_time))
}
}
impl TryFrom<crate::DateTime> for jiff::Zoned {
type Error = jiff::Error;
fn try_from(dt: crate::DateTime) -> Result<Self, Self::Error> {
let naive_date = jiff::civil::Date::try_from(dt.date)?;
let naive_time = jiff::civil::Time::try_from(dt.time.clone())?;
let naive_datetime = naive_date.to_datetime(naive_time);
let mut tz = crate::Time::jiff_fixed_tz(dt.time.offset)?;
if let Some(z) = dt.time.time_zone {
match z {
crate::TimeZone::Named { zone } => {
tz = jiff::tz::TimeZone::get(&zone.identifier)?;
}
crate::TimeZone::Fixed { offset } => {
tz = crate::Time::jiff_fixed_tz(Some(offset))?;
}
}
}
naive_datetime.to_zoned(tz)
}
}
impl crate::DateTime {
pub fn into_datetime(self) -> Option<jiff::civil::DateTime> {
jiff::civil::DateTime::try_from(self).ok()
}
pub fn into_zoned(self) -> Option<jiff::Zoned> {
jiff::Zoned::try_from(self).ok()
}
}
impl TryFrom<crate::Duration> for jiff::Span {
type Error = jiff::Error;
fn try_from(d: crate::Duration) -> Result<Self, Self::Error> {
let ms = d.milliseconds.unwrap_or(0.0).trunc();
let ns = (d.milliseconds.unwrap_or(0.0).fract() * 1_000_000.0).round();
Ok(jiff::Span::new()
.years(d.years)
.months(d.months)
.weeks(d.weeks)
.days(d.days)
.hours(d.hours)
.minutes(d.minutes)
.seconds(d.seconds)
.milliseconds(ms as i64)
.nanoseconds(ns as i64))
}
}
#[cfg(test)]
mod date_and_time {
use crate::Offset;
use crate::TimeZone;
use core::convert::TryFrom;
#[test]
fn time_from_hms() {
let iso = crate::Time {
hour: 23,
minute: 40,
second: 0,
millisecond: 0,
offset: Default::default(),
time_zone: None,
calendar: None,
};
let time = jiff::civil::Time::try_from(iso).unwrap();
assert_eq!(time.hour(), 23);
assert_eq!(time.minute(), 40);
assert_eq!(time.second(), 0);
}
#[test]
fn date_from_ymd() {
let iso = crate::Date::YMD {
year: 2023,
month: 2,
day: 8,
};
let date = jiff::civil::Date::try_from(iso).unwrap();
assert_eq!(date.year(), 2023);
assert_eq!(date.month() as u8, 2);
assert_eq!(date.day(), 8);
}
#[test]
fn datetime_from_ymd_hms() {
let dt = crate::DateTime {
date: crate::Date::YMD {
year: 2024,
month: 3,
day: 9,
},
time: crate::Time {
hour: 23,
minute: 40,
second: 0,
millisecond: 0,
offset: Default::default(),
time_zone: None,
calendar: None,
},
};
let datetime = jiff::Zoned::try_from(dt).unwrap();
assert_eq!(datetime.year(), 2024);
assert_eq!(datetime.month() as u8, 3);
assert_eq!(datetime.day(), 9);
assert_eq!(datetime.hour(), 23);
assert_eq!(datetime.minute(), 40);
assert_eq!(datetime.second(), 0);
}
#[test]
fn datetime_from_ymd_hms_with_offset() {
let dt = crate::DateTime {
date: crate::Date::YMD {
year: 2024,
month: 3,
day: 9,
},
time: crate::Time {
hour: 23,
minute: 40,
second: 0,
millisecond: 0,
offset: Some(Offset::Fixed {
hours: 2,
minutes: 0,
critical: false,
}),
time_zone: None,
calendar: None,
},
};
let datetime = jiff::Zoned::try_from(dt).unwrap();
assert_eq!(datetime.year(), 2024);
assert_eq!(datetime.month() as u8, 3);
assert_eq!(datetime.day(), 9);
assert_eq!(datetime.hour(), 23);
assert_eq!(datetime.minute(), 40);
assert_eq!(datetime.second(), 0);
assert_eq!(
datetime.time_zone().to_fixed_offset().unwrap().seconds(),
2 * 3600
);
}
#[test]
fn datetime_from_ymd_hms_with_matching_offset() {
let dt = crate::DateTime {
date: crate::Date::YMD {
year: 2024,
month: 3,
day: 9,
},
time: crate::Time {
hour: 23,
minute: 40,
second: 0,
millisecond: 0,
offset: Some(Offset::Fixed {
hours: 2,
minutes: 0,
critical: false,
}),
time_zone: Some(TimeZone::Fixed {
offset: Offset::Fixed {
hours: 3,
minutes: 0,
critical: false,
},
}),
calendar: None,
},
};
let datetime = jiff::Zoned::try_from(dt).unwrap();
assert_eq!(datetime.year(), 2024);
assert_eq!(datetime.month() as u8, 3);
assert_eq!(datetime.day(), 9);
assert_eq!(datetime.hour(), 23);
assert_eq!(datetime.minute(), 40);
assert_eq!(datetime.second(), 0);
assert_eq!(
datetime.time_zone().to_fixed_offset().unwrap().seconds(),
3 * 3600
);
}
#[test]
fn datetime_from_ymd_hms_with_named_zone() {
let dt = crate::DateTime {
date: crate::Date::YMD {
year: 2024,
month: 3,
day: 9,
},
time: crate::Time {
hour: 23,
minute: 40,
second: 0,
millisecond: 0,
offset: Some(Offset::Fixed {
hours: 2,
minutes: 0,
critical: false,
}),
time_zone: Some(TimeZone::Named {
zone: crate::NamedTimeZone {
identifier: "Europe/Berlin".to_string(),
critical: false,
},
}),
calendar: None,
},
};
let datetime = jiff::Zoned::try_from(dt).unwrap();
assert_eq!(datetime.year(), 2024);
assert_eq!(datetime.month() as u8, 3);
assert_eq!(datetime.day(), 9);
assert_eq!(datetime.hour(), 23);
assert_eq!(datetime.minute(), 40);
assert_eq!(datetime.second(), 0);
assert_eq!(datetime.time_zone().iana_name().unwrap(), "Europe/Berlin");
}
#[test]
fn date_from_yddd() {
let dt = crate::Date::Ordinal {
year: 2024,
day: 122,
};
let date = jiff::civil::Date::try_from(dt).unwrap();
assert_eq!(date, jiff::civil::date(2024, 5, 1));
}
#[test]
fn span_from_duration() {
let d = crate::Duration {
years: 5,
months: 4,
weeks: 3,
hours: 2,
days: 1,
minutes: 30,
seconds: 15,
milliseconds: Some(500.544),
};
let s = jiff::Span::try_from(d).unwrap();
assert_eq!(s.get_years(), 5);
assert_eq!(s.get_months(), 4);
assert_eq!(s.get_weeks(), 3);
assert_eq!(s.get_hours(), 2);
assert_eq!(s.get_minutes(), 30);
assert_eq!(s.get_seconds(), 15);
assert_eq!(s.get_milliseconds(), 500);
assert_eq!(s.get_nanoseconds(), 544006);
}
}