use {
crate::{
ATTOS_PER_NS, Meridiem, Offset, TimeParts, Weekday, an_err,
error::{DtErr, DtErrKind},
},
alloc::string::String,
core::result::Result,
jiff::{
Timestamp, Zoned,
fmt::strtime::{BrokenDownTime, Meridiem as JiffMeridiem},
tz::Offset as JiffOffset,
},
};
impl TimeParts {
pub fn to_jiff_broken_down_time(&self) -> Result<BrokenDownTime, DtErr> {
let mut bdt = BrokenDownTime::default();
if let Some(year) = self.yr {
let y: i16 = year
.try_into()
.map_err(|e| an_err!(DtErrKind::InvalidInput, "year: {}: {}", year, e))?;
bdt.set_year(Some(y))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "year: {}: {}", y, e))?;
}
if let Some(m) = self.mo {
bdt.set_month(Some(m as i8))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "month: {}: {}", m, e))?;
}
if let Some(d) = self.day {
bdt.set_day(Some(d as i8))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "day: {}: {}", d, e))?;
}
if let Some(doy) = self.day_of_yr {
bdt.set_day_of_year(Some(doy as i16))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "doy: {}: {}", doy, e))?;
}
if let Some(y) = self.iso_wk_yr {
let y: i16 = y
.try_into()
.map_err(|e| an_err!(DtErrKind::InvalidInput, "iso wk yr: {}: {}", y, e))?;
bdt.set_iso_week_year(Some(y))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "iso wk yr: {}: {}", y, e))?;
}
if let Some(w) = self.iso_wk {
bdt.set_iso_week(Some(w as i8))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "iso wk: {}: {}", w, e))?;
}
if let Some(w) = self.wk_sun {
bdt.set_sunday_based_week(Some(w as i8))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "sun based wk: {}: {}", w, e))?;
}
if let Some(w) = self.wk_mon {
bdt.set_monday_based_week(Some(w as i8))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "mon based wk: {}: {}", w, e))?;
}
if let Some(h) = self.hr {
bdt.set_hour(Some(h as i8))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "hour: {}: {}", h, e))?;
}
if let Some(m) = self.min {
bdt.set_minute(Some(m as i8))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "minute: {}: {}", m, e))?;
}
if let Some(s) = self.sec {
let non_ls_s = if s == 60 { 59 } else { s };
bdt.set_second(Some(non_ls_s as i8))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "second: {}: {}", non_ls_s, e))?;
}
if let Some(attos) = self.attos {
let ns_u64 = attos / ATTOS_PER_NS;
let ns: i32 = if ns_u64 >= 1_000_000_000 {
999_999_999
} else {
ns_u64 as i32
};
bdt.set_subsec_nanosecond(Some(ns))
.map_err(|e| an_err!(DtErrKind::InvalidItem, "ns: {}: {}", ns, e))?;
}
if let Some(wd) = self.wkday {
let jwd = match wd {
Weekday::Sunday => jiff::civil::Weekday::Sunday,
Weekday::Monday => jiff::civil::Weekday::Monday,
Weekday::Tuesday => jiff::civil::Weekday::Tuesday,
Weekday::Wednesday => jiff::civil::Weekday::Wednesday,
Weekday::Thursday => jiff::civil::Weekday::Thursday,
Weekday::Friday => jiff::civil::Weekday::Friday,
Weekday::Saturday => jiff::civil::Weekday::Saturday,
};
bdt.set_weekday(Some(jwd));
}
if let Some(mer) = self.meridiem {
let jmer = match mer {
Meridiem::AM => JiffMeridiem::AM,
Meridiem::PM => JiffMeridiem::PM,
};
bdt.set_meridiem(Some(jmer));
}
if let Some(secs) = self.unix_timestamp_seconds {
let ts = Timestamp::from_second(secs)
.map_err(|e| an_err!(DtErrKind::InvalidInput, "timestamp: {}: {}", secs, e))?;
bdt.set_timestamp(Some(ts));
}
if let Some(name) = &self.iana_name {
match name.as_str() {
Ok(s) if !s.is_empty() => bdt.set_iana_time_zone(Some(String::from(s))),
Ok(_) => {} Err(e) => {
return Err(an_err!(
DtErrKind::InvalidBytes,
"invalid iana ascii: {:?}: {}",
name,
e
));
}
}
} else if let Some(Offset::Fixed(secs)) = self.offset {
if let Ok(jiff_offset) = JiffOffset::from_seconds(secs) {
bdt.set_offset(Some(jiff_offset));
} else {
return Err(an_err!(
DtErrKind::InvalidTimezoneOffset,
"offset secs: {}",
secs
));
}
} else {
bdt.set_offset(Some(JiffOffset::UTC));
}
Ok(bdt)
}
pub fn to_jiff_zoned(&self) -> Result<Zoned, DtErr> {
let bdt = self.to_jiff_broken_down_time()?;
if let Ok(zoned) = bdt.to_zoned() {
return Ok(zoned);
}
if let Ok(ts) = bdt.to_timestamp()
&& let Ok(zoned) = ts.in_tz("UTC")
{
return Ok(zoned);
}
if let Ok(dt) = bdt.to_datetime()
&& let Ok(zoned) = dt.in_tz("UTC")
{
return Ok(zoned);
}
if let Ok(date) = bdt.to_date()
&& let Ok(dt) = date.at(0, 0, 0, 0).in_tz("UTC")
{
return Ok(dt);
}
Err(an_err!(
DtErrKind::InvalidInput,
"could not convert to jiff zoned"
))
}
#[inline]
pub fn to_jiff_timestamp(&self) -> Result<Timestamp, DtErr> {
self.to_jiff_zoned().map(|z| z.timestamp())
}
}