#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)]
use crate::Time;
use calendrical_calculations::rata_die::RataDie;
use core::ops::Deref;
use icu_calendar::{Date, Iso};
use icu_provider::prelude::*;
use tinystr::TinyAsciiStr;
use zerovec::maps::ZeroMapKV;
use zerovec::ule::{AsULE, ULE};
use zerovec::{ZeroMap2d, ZeroSlice, ZeroVec};
pub mod iana;
pub mod windows;
#[cfg(feature = "compiled_data")]
#[derive(Debug)]
pub struct Baked;
#[cfg(feature = "compiled_data")]
#[allow(unused_imports)]
const _: () = {
use icu_time_data::*;
pub mod icu {
pub use crate as time;
}
make_provider!(Baked);
impl_time_zone_iana_map_v1!(Baked);
impl_time_zone_iana_names_v1!(Baked);
impl_time_zone_windows_v1!(Baked);
impl_time_zone_offsets_v1!(Baked);
};
#[cfg(feature = "datagen")]
pub const MARKERS: &[DataMarkerInfo] = &[
iana::TimeZoneIanaNamesV1::INFO,
iana::TimeZoneIanaMapV1::INFO,
windows::TimeZoneWindowsV1::INFO,
TimeZoneOffsetsV1::INFO,
];
#[repr(transparent)]
#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd, yoke::Yokeable, ULE, Hash)]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_time::provider))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
pub struct TimeZone(pub TinyAsciiStr<8>);
impl TimeZone {
pub const fn unknown() -> Self {
Self(tinystr::tinystr!(8, "unk"))
}
}
impl Deref for TimeZone {
type Target = TinyAsciiStr<8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl AsULE for TimeZone {
type ULE = Self;
#[inline]
fn to_unaligned(self) -> Self::ULE {
self
}
#[inline]
fn from_unaligned(unaligned: Self::ULE) -> Self {
unaligned
}
}
impl<'a> zerovec::maps::ZeroMapKV<'a> for TimeZone {
type Container = ZeroVec<'a, TimeZone>;
type Slice = ZeroSlice<TimeZone>;
type GetType = TimeZone;
type OwnedType = TimeZone;
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[zerovec::make_ule(TimeZoneVariantULE)]
#[repr(u8)]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_time))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[non_exhaustive]
pub enum TimeZoneVariant {
Standard = 0,
Daylight = 1,
}
pub type EighthsOfHourOffset = i8;
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug)]
pub struct MinutesSinceEpoch(pub i32);
impl From<(Date<Iso>, Time)> for MinutesSinceEpoch {
fn from((d, t): (Date<Iso>, Time)) -> MinutesSinceEpoch {
Self(
((Iso::to_fixed(d) - Self::EPOCH) as i32 * 24 + t.hour.number() as i32) * 60
+ t.minute.number() as i32,
)
}
}
impl MinutesSinceEpoch {
const EPOCH: RataDie = RataDie::new(719163);
}
impl AsULE for MinutesSinceEpoch {
type ULE = <i32 as AsULE>::ULE;
fn from_unaligned(unaligned: Self::ULE) -> Self {
Self(i32::from_unaligned(unaligned))
}
fn to_unaligned(self) -> Self::ULE {
self.0.to_unaligned()
}
}
impl<'a> ZeroMapKV<'a> for MinutesSinceEpoch {
type Container = ZeroVec<'a, Self>;
type Slice = ZeroSlice<Self>;
type GetType = <Self as AsULE>::ULE;
type OwnedType = Self;
}
#[cfg(feature = "serde")]
impl serde::Serialize for MinutesSinceEpoch {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
#[cfg(feature = "alloc")]
if serializer.is_human_readable() {
let minute = self.0 % 60;
let hour = self.0 / 60 % 24;
let days = self.0 / 60 / 24;
let date = Iso::from_fixed(Self::EPOCH + days as i64);
let year = date.year().extended_year;
let month = date.month().month_number();
let day = date.day_of_month().0;
return serializer.serialize_str(&alloc::format!(
"{year:04}-{month:02}-{day:02} {hour:02}:{minute:02}"
));
}
serializer.serialize_i32(self.0)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for MinutesSinceEpoch {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[cfg(feature = "alloc")]
if deserializer.is_human_readable() {
use serde::de::Error;
let e0 = D::Error::custom("invalid");
let e1 = |_| D::Error::custom("invalid");
let e2 = |_| D::Error::custom("invalid");
let e3 = |_| D::Error::custom("invalid");
let parts = alloc::borrow::Cow::<'de, str>::deserialize(deserializer)?;
if parts.len() != 16 {
return Err(e0);
}
let year = parts[0..4].parse::<i32>().map_err(e1)?;
let month = parts[5..7].parse::<u8>().map_err(e1)?;
let day = parts[8..10].parse::<u8>().map_err(e1)?;
let hour = parts[11..13].parse::<u8>().map_err(e1)?;
let minute = parts[14..16].parse::<u8>().map_err(e1)?;
return Ok(Self::from((
Date::try_new_iso(year, month, day).map_err(e2)?,
Time::try_new(hour, minute, 0, 0).map_err(e3)?,
)));
}
i32::deserialize(deserializer).map(Self)
}
}
icu_provider::data_marker!(
TimeZoneOffsetsV1,
"time/zone/offsets/v1",
ZeroMap2d<'static, TimeZone, MinutesSinceEpoch, (EighthsOfHourOffset, EighthsOfHourOffset)>,
is_singleton = true
);