timezone.rs (9381B)
1 // This file is part of ICU4X. For terms of use, please see the file 2 // called LICENSE at the top level of the ICU4X source tree 3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). 4 5 use ffi::TimeZoneInfo; 6 7 #[diplomat::bridge] 8 #[diplomat::abi_rename = "icu4x_{0}_mv1"] 9 #[diplomat::attr(auto, namespace = "icu4x")] 10 pub mod ffi { 11 use alloc::boxed::Box; 12 13 use crate::unstable::{ 14 date::ffi::IsoDate, 15 datetime::ffi::IsoDateTime, 16 time::ffi::Time, 17 variant_offset::ffi::{UtcOffset, VariantOffsetsCalculator}, 18 }; 19 20 #[diplomat::opaque] 21 #[diplomat::rust_link(icu::time::TimeZone, Struct)] 22 pub struct TimeZone(pub(crate) icu_time::TimeZone); 23 24 impl TimeZone { 25 /// The unknown time zone. 26 #[diplomat::rust_link(icu::time::TimeZoneInfo::unknown, FnInStruct)] 27 #[diplomat::rust_link(icu::time::TimeZone::unknown, FnInStruct, hidden)] 28 #[diplomat::attr(auto, named_constructor)] 29 pub fn unknown() -> Box<TimeZone> { 30 Box::new(TimeZone(icu_time::TimeZone::UNKNOWN)) 31 } 32 33 /// Whether the time zone is the unknown zone. 34 #[diplomat::rust_link(icu::time::TimeZone::is_unknown, FnInStruct)] 35 pub fn is_unknown(&self) -> bool { 36 self.0.is_unknown() 37 } 38 39 /// Creates a time zone from a BCP-47 string. 40 /// 41 /// Returns the unknown time zone if the string is not a valid BCP-47 subtag. 42 #[diplomat::rust_link(icu::time::TimeZone, Struct, compact)] 43 #[diplomat::attr(auto, named_constructor = "from_bcp47")] 44 #[diplomat::demo(default_constructor)] 45 pub fn create_from_bcp47(id: &DiplomatStr) -> Box<Self> { 46 icu_locale_core::subtags::Subtag::try_from_utf8(id) 47 .map(icu_time::TimeZone) 48 .map(TimeZone) 49 .map(Box::new) 50 .unwrap_or(Self::unknown()) 51 } 52 53 #[diplomat::rust_link(icu::time::TimeZone::with_offset, FnInStruct)] 54 pub fn with_offset(&self, offset: &UtcOffset) -> Box<TimeZoneInfo> { 55 Box::new(self.0.with_offset(Some(offset.0)).into()) 56 } 57 58 #[diplomat::rust_link(icu::time::TimeZone::without_offset, FnInStruct)] 59 pub fn without_offset(&self) -> Box<TimeZoneInfo> { 60 Box::new(self.0.without_offset().into()) 61 } 62 } 63 64 #[diplomat::enum_convert(icu_time::zone::TimeZoneVariant, needs_wildcard)] 65 pub enum TimeZoneVariant { 66 Standard, 67 Daylight, 68 } 69 70 impl TimeZoneVariant { 71 /// Sets the `variant` field to "daylight" time. 72 #[diplomat::rust_link(icu::time::zone::TimeZoneVariant::from_rearguard_isdst, FnInEnum)] 73 #[diplomat::rust_link(icu::time::TimeZoneInfo::with_variant, FnInStruct)] 74 #[diplomat::rust_link(icu::time::zone::TimeZoneVariant, Enum, compact)] 75 pub fn from_rearguard_isdst(&mut self, isdst: bool) -> Self { 76 icu_time::zone::TimeZoneVariant::from_rearguard_isdst(isdst).into() 77 } 78 } 79 80 #[diplomat::opaque] 81 #[diplomat::rust_link(icu::time::TimeZoneInfo, Struct)] 82 #[diplomat::rust_link(icu::time::zone::models::AtTime, Struct, hidden)] 83 #[diplomat::rust_link(icu::time::zone::models::Base, Struct, hidden)] 84 #[diplomat::rust_link(icu::time::zone::models::Full, Struct, hidden)] 85 pub struct TimeZoneInfo { 86 pub(crate) id: icu_time::TimeZone, 87 pub(crate) offset: Option<icu_time::zone::UtcOffset>, 88 pub(crate) variant: Option<icu_time::zone::TimeZoneVariant>, 89 pub(crate) zone_name_timestamp: Option<icu_time::zone::ZoneNameTimestamp>, 90 } 91 92 impl TimeZoneInfo { 93 /// Creates a time zone for UTC (Coordinated Universal Time). 94 #[diplomat::rust_link(icu::time::TimeZoneInfo::utc, FnInStruct)] 95 #[diplomat::rust_link(icu::time::zone::UtcOffset::zero, FnInStruct, hidden)] 96 #[diplomat::attr(auto, named_constructor)] 97 pub fn utc() -> Box<TimeZoneInfo> { 98 Box::new(icu_time::TimeZoneInfo::utc().into()) 99 } 100 101 /// Creates a time zone info from parts. 102 #[diplomat::attr(auto, constructor)] 103 pub fn from_parts( 104 id: &TimeZone, 105 offset: Option<&UtcOffset>, 106 variant: Option<TimeZoneVariant>, 107 ) -> Box<TimeZoneInfo> { 108 Box::new(Self { 109 id: id.0, 110 offset: offset.map(|o| o.0), 111 variant: variant.map(Into::into), 112 zone_name_timestamp: None, 113 }) 114 } 115 116 #[diplomat::rust_link(icu::time::TimeZoneInfo::id, FnInStruct)] 117 pub fn id(&self) -> Box<TimeZone> { 118 Box::new(TimeZone(self.id)) 119 } 120 121 /// Sets the datetime at which to interpret the time zone 122 /// for display name lookup. 123 /// 124 /// Notes: 125 /// 126 /// - If not set, the formatting datetime is used if possible. 127 /// - The constraints are the same as with `ZoneNameTimestamp` in Rust. 128 /// - Set to year 1000 or 9999 for a reference far in the past or future. 129 #[diplomat::rust_link(icu::time::TimeZoneInfo::at_date_time_iso, FnInStruct)] 130 #[diplomat::rust_link(icu::time::zone::ZoneNameTimestamp, Struct, compact)] 131 #[diplomat::rust_link( 132 icu::time::TimeZoneInfo::with_zone_name_timestamp, 133 FnInStruct, 134 hidden 135 )] 136 #[diplomat::rust_link( 137 icu::time::zone::ZoneNameTimestamp::from_date_time_iso, 138 FnInStruct, 139 hidden 140 )] 141 #[diplomat::rust_link( 142 icu::time::zone::ZoneNameTimestamp::far_in_future, 143 FnInStruct, 144 hidden 145 )] // documented 146 #[diplomat::rust_link(icu::time::zone::ZoneNameTimestamp::far_in_past, FnInStruct, hidden)] // documented 147 pub fn at_date_time_iso(&self, date: &IsoDate, time: &Time) -> Box<Self> { 148 Box::new(Self { 149 zone_name_timestamp: Some(icu_time::zone::ZoneNameTimestamp::from_date_time_iso( 150 icu_time::DateTime { 151 date: date.0, 152 time: time.0, 153 }, 154 )), 155 ..*self 156 }) 157 } 158 159 #[diplomat::rust_link(icu::time::TimeZoneInfo::zone_name_timestamp, FnInStruct)] 160 #[diplomat::rust_link( 161 icu::time::zone::ZoneNameTimestamp::to_date_time_iso, 162 FnInStruct, 163 hidden 164 )] 165 pub fn zone_name_date_time(&self) -> Option<IsoDateTime> { 166 let datetime = self.zone_name_timestamp?.to_date_time_iso(); 167 Some(IsoDateTime { 168 date: Box::new(IsoDate(datetime.date)), 169 time: Box::new(Time(datetime.time)), 170 }) 171 } 172 173 #[diplomat::rust_link(icu::time::TimeZoneInfo::with_variant, FnInStruct)] 174 pub fn with_variant(&self, time_variant: TimeZoneVariant) -> Box<Self> { 175 Box::new(Self { 176 variant: Some(time_variant.into()), 177 ..*self 178 }) 179 } 180 181 /// Infers the zone variant. 182 /// 183 /// Requires the offset and local time to be set. 184 #[diplomat::rust_link(icu::time::TimeZoneInfo::infer_variant, FnInStruct)] 185 #[diplomat::rust_link(icu::time::zone::TimeZoneVariant, Enum, compact)] 186 pub fn infer_variant( 187 &mut self, 188 offset_calculator: &VariantOffsetsCalculator, 189 ) -> Option<()> { 190 let info = self 191 .id 192 .with_offset(self.offset) 193 .with_zone_name_timestamp(self.zone_name_timestamp?) 194 .infer_variant(offset_calculator.0.as_borrowed()); 195 196 self.id = info.id(); 197 self.variant = Some(info.variant()); 198 Some(()) 199 } 200 201 #[diplomat::rust_link(icu::time::TimeZoneInfo::variant, FnInStruct)] 202 pub fn variant(&self) -> Option<TimeZoneVariant> { 203 self.variant.map(Into::into) 204 } 205 } 206 } 207 208 impl From<icu_time::zone::UtcOffset> for TimeZoneInfo { 209 fn from(other: icu_time::zone::UtcOffset) -> Self { 210 Self { 211 id: icu_time::TimeZone::UNKNOWN, 212 offset: Some(other), 213 variant: None, 214 zone_name_timestamp: None, 215 } 216 } 217 } 218 219 impl From<icu_time::TimeZoneInfo<icu_time::zone::models::Base>> for TimeZoneInfo { 220 fn from(other: icu_time::TimeZoneInfo<icu_time::zone::models::Base>) -> Self { 221 Self { 222 id: other.id(), 223 offset: other.offset(), 224 variant: None, 225 zone_name_timestamp: None, 226 } 227 } 228 } 229 230 impl From<icu_time::TimeZoneInfo<icu_time::zone::models::AtTime>> for TimeZoneInfo { 231 fn from(other: icu_time::TimeZoneInfo<icu_time::zone::models::AtTime>) -> Self { 232 Self { 233 id: other.id(), 234 offset: other.offset(), 235 variant: None, 236 zone_name_timestamp: Some(other.zone_name_timestamp()), 237 } 238 } 239 } 240 241 impl From<icu_time::TimeZoneInfo<icu_time::zone::models::Full>> for TimeZoneInfo { 242 fn from(other: icu_time::TimeZoneInfo<icu_time::zone::models::Full>) -> Self { 243 Self { 244 id: other.id(), 245 offset: other.offset(), 246 variant: Some(other.variant()), 247 zone_name_timestamp: Some(other.zone_name_timestamp()), 248 } 249 } 250 }