// This file is part of ICU4X. For terms of use, please see the file // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use ffi::TimeZoneInfo; #[diplomat::bridge] #[diplomat::abi_rename = "icu4x_{0}_mv1"] #[diplomat::attr(auto, namespace = "icu4x")] pub mod ffi { use alloc::boxed::Box; use crate::{ date::ffi::IsoDate, datetime::ffi::IsoDateTime, time::ffi::Time, utc_offset::ffi::{UtcOffset, UtcOffsetCalculator}, }; #[diplomat::opaque] #[diplomat::rust_link(icu::time::TimeZone, Struct)] pub struct TimeZone(pub(crate) icu_time::TimeZone); impl TimeZone { /// The unknown time zone. #[diplomat::rust_link(icu::time::TimeZoneInfo::unknown, FnInStruct)] #[diplomat::rust_link(icu::time::TimeZone::unknown, FnInStruct, hidden)] #[diplomat::attr(auto, named_constructor)] pub fn unknown() -> Box { Box::new(TimeZone(icu_time::TimeZone::unknown())) } /// Creates a time zone from a BCP-47 string. /// /// Returns the unknown time zone if the string is not a valid BCP-47 subtag. #[diplomat::rust_link(icu::time::TimeZone, Struct, compact)] #[diplomat::rust_link(icu::time::TimeZone::from_str, FnInStruct, hidden)] #[diplomat::rust_link(icu::time::TimeZone::deref, FnInStruct, hidden)] #[diplomat::rust_link(icu::time::TimeZone::Target, AssociatedTypeInStruct, hidden)] #[diplomat::attr(auto, named_constructor = "from_bcp47")] #[diplomat::demo(default_constructor)] pub fn create_from_bcp47(id: &DiplomatStr) -> Box { tinystr::TinyAsciiStr::try_from_utf8(id) .map(icu_time::TimeZone) .map(TimeZone) .map(Box::new) .unwrap_or(Self::unknown()) } #[diplomat::rust_link(icu::time::TimeZone::with_offset, FnInStruct)] pub fn with_offset(&self, offset: &UtcOffset) -> Box { Box::new(self.0.with_offset(Some(offset.0)).into()) } #[diplomat::rust_link(icu::time::TimeZone::without_offset, FnInStruct)] pub fn without_offset(&self) -> Box { Box::new(self.0.without_offset().into()) } } #[diplomat::enum_convert(icu_time::zone::TimeZoneVariant, needs_wildcard)] pub enum TimeZoneVariant { Standard, Daylight, } impl TimeZoneVariant { /// Sets the `zone_variant` field to "daylight" time. #[diplomat::rust_link(icu::time::zone::TimeZoneVariant::from_rearguard_isdst, FnInEnum)] #[diplomat::rust_link(icu::time::TimeZoneInfo::with_zone_variant, FnInStruct)] #[diplomat::rust_link(icu::time::zone::TimeZoneVariant, Enum, compact)] pub fn from_rearguard_isdst(&mut self, isdst: bool) -> Self { icu_time::zone::TimeZoneVariant::from_rearguard_isdst(isdst).into() } } #[diplomat::opaque] #[diplomat::rust_link(icu::time::TimeZoneInfo, Struct)] #[diplomat::rust_link(icu::time::zone::models::AtTime, Enum, hidden)] #[diplomat::rust_link(icu::time::zone::models::Base, Enum, hidden)] #[diplomat::rust_link(icu::time::zone::models::Full, Enum, hidden)] pub struct TimeZoneInfo { pub(crate) time_zone_id: icu_time::TimeZone, pub(crate) offset: Option, pub(crate) zone_variant: Option, pub(crate) local_time: Option<(icu_calendar::Date, icu_time::Time)>, } impl TimeZoneInfo { /// Creates a time zone for UTC (Coordinated Universal Time). #[diplomat::rust_link(icu::time::TimeZoneInfo::utc, FnInStruct)] #[diplomat::rust_link(icu::time::zone::UtcOffset::zero, FnInStruct, hidden)] #[diplomat::attr(auto, named_constructor)] pub fn utc() -> Box { Box::new(icu_time::TimeZoneInfo::utc().into()) } /// Creates a time zone info from parts. #[diplomat::attr(auto, constructor)] pub fn from_parts( time_zone_id: &TimeZone, offset: Option<&UtcOffset>, zone_variant: Option, ) -> Box { Box::new(Self { time_zone_id: time_zone_id.0, offset: offset.map(|o| o.0), zone_variant: zone_variant.map(Into::into), local_time: None, }) } #[diplomat::rust_link(icu::time::TimeZoneInfo::time_zone_id, FnInStruct)] pub fn time_zone_id(&self) -> Box { Box::new(TimeZone(self.time_zone_id)) } #[diplomat::rust_link(icu::time::TimeZoneInfo::at_time, FnInStruct)] pub fn at_time(&self, date: &IsoDate, time: &Time) -> Box { Box::new(Self { local_time: Some((date.0, time.0)), ..*self }) } #[diplomat::rust_link(icu::time::TimeZoneInfo::local_time, FnInStruct)] pub fn local_time(&self) -> Option { Some(IsoDateTime { date: Box::new(IsoDate(self.local_time?.0)), time: Box::new(Time(self.local_time?.1)), }) } #[diplomat::rust_link(icu::time::TimeZoneInfo::with_zone_variant, FnInStruct)] pub fn with_zone_variant(&self, time_zone_variant: TimeZoneVariant) -> Box { Box::new(Self { zone_variant: Some(time_zone_variant.into()), ..*self }) } /// Infers the zone variant. /// /// Requires the offset and local time to be set. #[diplomat::rust_link(icu::time::TimeZoneInfo::infer_zone_variant, FnInStruct)] #[diplomat::rust_link(icu::time::zone::TimeZoneVariant, Enum, compact)] pub fn infer_zone_variant( &mut self, offset_calculator: &UtcOffsetCalculator, ) -> Option<()> { let info = self .time_zone_id .with_offset(self.offset) .at_time(self.local_time?) .infer_zone_variant(&offset_calculator.0); self.time_zone_id = info.time_zone_id(); self.zone_variant = Some(info.zone_variant()); Some(()) } #[diplomat::rust_link(icu::time::TimeZoneInfo::zone_variant, FnInStruct)] pub fn zone_variant(&self) -> Option { self.zone_variant.map(Into::into) } } } impl From for TimeZoneInfo { fn from(other: icu_time::zone::UtcOffset) -> Self { Self { time_zone_id: icu_time::TimeZone::unknown(), offset: Some(other), zone_variant: None, local_time: None, } } } impl From> for TimeZoneInfo { fn from(other: icu_time::TimeZoneInfo) -> Self { Self { time_zone_id: other.time_zone_id(), offset: other.offset(), zone_variant: None, local_time: None, } } } impl From> for TimeZoneInfo { fn from(other: icu_time::TimeZoneInfo) -> Self { Self { time_zone_id: other.time_zone_id(), offset: other.offset(), zone_variant: None, local_time: Some(other.local_time()), } } } impl From> for TimeZoneInfo { fn from(other: icu_time::TimeZoneInfo) -> Self { Self { time_zone_id: other.time_zone_id(), offset: other.offset(), zone_variant: Some(other.zone_variant()), local_time: Some(other.local_time()), } } }