use crate::{AsciiStr, Dt, Weekday};
mod to_str;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct YmdHms {
pub yr: i64,
pub mo: u8,
pub day: u8,
pub hr: u8,
pub min: u8,
pub sec: u8, pub attos: u64, pub unix_attosec: i128,
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "js", derive(tsify::Tsify))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct GregorianTime {
pub(crate) unix_attosec: i128,
pub(crate) yr: i64,
pub(crate) mo: u8,
pub(crate) day: u8,
pub(crate) hr: u8,
pub(crate) min: u8,
pub(crate) sec: u8,
pub(crate) attos: u64,
pub(crate) iso_yr: i64,
pub(crate) iso_wk: u8,
pub(crate) iso_wkday: Weekday,
pub(crate) day_of_yr: u16,
pub(crate) wkday: u8,
pub(crate) wk_of_yr_sun: u8,
pub(crate) wk_of_yr_mon: u8,
pub(crate) offset_sec: Option<i32>,
pub(crate) tz: Option<AsciiStr<49>>,
pub(crate) tz_abbrev: Option<AsciiStr<49>>,
}
impl GregorianTime {
#[inline]
pub const fn new(
unix_attosec: i128,
yr: i64,
mo: u8,
day: u8,
hr: u8,
min: u8,
sec: u8,
attos: u64,
iso_yr: i64,
iso_wk: u8,
iso_wkday: Weekday,
day_of_yr: u16,
wkday: u8,
wk_of_yr_sun: u8,
wk_of_yr_mon: u8,
) -> Self {
Self {
unix_attosec,
yr,
mo,
day,
hr,
min,
sec,
attos,
iso_yr,
iso_wk,
iso_wkday,
day_of_yr,
wkday,
wk_of_yr_sun,
wk_of_yr_mon,
offset_sec: None,
tz: None,
tz_abbrev: None,
}
}
#[inline]
pub const fn unix_attosec(&self) -> i128 {
self.unix_attosec
}
#[inline]
pub const fn unix_timestamp(&self) -> (i64, u64) {
const ATTOS_PER_SEC_I128: i128 = 1_000_000_000_000_000_000;
let total = self.unix_attosec;
let secs = (total / ATTOS_PER_SEC_I128) as i64;
let frac = (total % ATTOS_PER_SEC_I128).unsigned_abs() as u64;
(secs, frac)
}
#[inline]
pub const fn yr(&self) -> i64 {
self.yr
}
#[inline]
pub const fn mo(&self) -> u8 {
self.mo
}
#[inline]
pub const fn day(&self) -> u8 {
self.day
}
#[inline]
pub const fn hr(&self) -> u8 {
self.hr
}
#[inline]
pub const fn min(&self) -> u8 {
self.min
}
#[inline]
pub const fn sec(&self) -> u8 {
self.sec
}
#[inline]
pub const fn attos(&self) -> u64 {
self.attos
}
#[inline]
pub const fn iso_yr(&self) -> i64 {
self.iso_yr
}
#[inline]
pub const fn iso_wk(&self) -> u8 {
self.iso_wk
}
#[inline]
pub const fn iso_wkday(&self) -> Weekday {
self.iso_wkday
}
#[inline]
pub const fn day_of_yr(&self) -> u16 {
self.day_of_yr
}
#[inline]
pub const fn wkday_sun(&self) -> u8 {
self.wkday
}
#[inline]
pub const fn wkday_mon(&self) -> u8 {
self.iso_wkday.wk_mon()
}
#[inline]
pub const fn wk_of_yr_sun(&self) -> u8 {
self.wk_of_yr_sun
}
#[inline]
pub const fn wk_of_yr_mon(&self) -> u8 {
self.wk_of_yr_mon
}
#[inline]
pub const fn offset_sec(&self) -> Option<i32> {
self.offset_sec
}
#[inline]
pub const fn tz(&self) -> Option<&AsciiStr<49>> {
self.tz.as_ref()
}
#[inline]
pub const fn tz_abbrev(&self) -> Option<&AsciiStr<49>> {
self.tz_abbrev.as_ref()
}
#[inline]
pub(crate) fn set_offset(&mut self, offset_sec: Option<i32>) -> &mut Self {
self.offset_sec = offset_sec;
self
}
#[inline]
pub(crate) fn set_tz(&mut self, tz: Option<&str>) -> &mut Self {
self.tz = tz.and_then(|s| AsciiStr::try_from_str(s).ok());
self
}
#[inline]
pub(crate) fn set_tz_abbrev(&mut self, tz_abbrev: Option<&str>) -> &mut Self {
self.tz_abbrev = tz_abbrev.and_then(|s| AsciiStr::try_from_str(s).ok());
self
}
#[inline]
pub const fn to_time_point(&self) -> Dt {
Dt::from_ymdhms(self.yr, self.mo, self.day, self.hr, self.min, self.sec, 0)
}
}
#[cfg(feature = "wire")]
impl GregorianTime {
pub const WIRE_VERSION: u8 = 1;
pub const WIRE_SIZE: usize = 158;
pub fn to_wire_bytes(&self) -> [u8; Self::WIRE_SIZE] {
let mut buf = [0u8; Self::WIRE_SIZE];
buf[0] = Self::WIRE_VERSION;
let mut offset = 1usize;
buf[offset..offset + 16].copy_from_slice(&self.unix_attosec.to_le_bytes());
offset += 16;
buf[offset..offset + 8].copy_from_slice(&self.yr.to_le_bytes());
offset += 8;
buf[offset] = self.mo;
offset += 1;
buf[offset] = self.day;
offset += 1;
buf[offset] = self.hr;
offset += 1;
buf[offset] = self.min;
offset += 1;
buf[offset] = self.sec;
offset += 1;
buf[offset..offset + 8].copy_from_slice(&self.attos.to_le_bytes());
offset += 8;
buf[offset..offset + 8].copy_from_slice(&self.iso_yr.to_le_bytes());
offset += 8;
buf[offset] = self.iso_wk;
offset += 1;
buf[offset] = self.iso_wkday.to_wire_byte();
offset += 1;
buf[offset..offset + 2].copy_from_slice(&self.day_of_yr.to_le_bytes());
offset += 2;
buf[offset] = self.wkday;
offset += 1;
buf[offset] = self.wk_of_yr_sun;
offset += 1;
buf[offset] = self.wk_of_yr_mon;
offset += 1;
if let Some(val) = self.offset_sec {
buf[offset] = 1;
buf[offset + 1..offset + 5].copy_from_slice(&val.to_le_bytes());
} else {
buf[offset] = 0;
}
offset += 5;
if let Some(tz) = &self.tz {
buf[offset] = 1;
let tz_bytes = tz.to_wire_bytes();
buf[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE].copy_from_slice(&tz_bytes);
} else {
buf[offset] = 0;
}
offset += 1 + AsciiStr::<49>::WIRE_SIZE;
if let Some(abbrev) = &self.tz_abbrev {
buf[offset] = 1;
let abbrev_bytes = abbrev.to_wire_bytes();
buf[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE].copy_from_slice(&abbrev_bytes);
} else {
buf[offset] = 0;
}
buf
}
pub fn from_wire_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() != Self::WIRE_SIZE {
return None;
}
if bytes[0] != Self::WIRE_VERSION {
return None;
}
let mut offset = 1usize;
let unix_attosec = i128::from_le_bytes(bytes[offset..offset + 16].try_into().ok()?);
offset += 16;
let yr = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
offset += 8;
let mo = bytes[offset];
offset += 1;
let day = bytes[offset];
offset += 1;
let hr = bytes[offset];
offset += 1;
let min = bytes[offset];
offset += 1;
let sec = bytes[offset];
offset += 1;
let attos = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
offset += 8;
let iso_yr = i64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?);
offset += 8;
let iso_wk = bytes[offset];
offset += 1;
let iso_wkday = Weekday::from_wire_byte(bytes[offset])?;
offset += 1;
let day_of_yr = u16::from_le_bytes(bytes[offset..offset + 2].try_into().ok()?);
offset += 2;
let wkday = bytes[offset];
offset += 1;
let wk_of_yr_sun = bytes[offset];
offset += 1;
let wk_of_yr_mon = bytes[offset];
offset += 1;
let offset_sec = if bytes[offset] == 1 {
Some(i32::from_le_bytes(
bytes[offset + 1..offset + 5].try_into().ok()?,
))
} else {
None
};
offset += 5;
let tz = if bytes[offset] == 1 {
AsciiStr::<49>::from_wire_bytes(
&bytes[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE],
)
} else {
None
};
offset += 1 + AsciiStr::<49>::WIRE_SIZE;
let tz_abbrev = if bytes[offset] == 1 {
AsciiStr::<49>::from_wire_bytes(
&bytes[offset + 1..offset + 1 + AsciiStr::<49>::WIRE_SIZE],
)
} else {
None
};
Some(Self {
unix_attosec,
yr,
mo,
day,
hr,
min,
sec,
attos,
iso_yr,
iso_wk,
iso_wkday,
day_of_yr,
wkday,
wk_of_yr_sun,
wk_of_yr_mon,
offset_sec,
tz,
tz_abbrev,
})
}
}