1use alloc::borrow::Cow;
8use icu_pattern::{DoublePlaceholderPattern, SinglePlaceholderPattern};
9use icu_provider::prelude::*;
10use icu_time::{zone::TimeZoneVariant, TimeZone};
11use zerovec::{ZeroMap, ZeroVec};
12
13pub use icu_time::provider::MetazoneId;
14
15pub(crate) mod tz {
17 pub(crate) use super::ExemplarCities;
18 pub(crate) use super::Locations;
19 pub(crate) use super::MetazoneGenericNames as MzGeneric;
20 pub(crate) use super::MetazoneSpecificNames as MzSpecific;
21 pub(crate) use super::TimeZoneEssentials as Essentials;
22 pub(crate) use super::TimezoneNamesCitiesOverrideV1 as CitiesOverrideV1;
23 pub(crate) use super::TimezoneNamesCitiesRootV1 as CitiesRootV1;
24 pub(crate) use super::TimezoneNamesEssentialsV1 as EssentialsV1;
25 pub(crate) use super::TimezoneNamesGenericLongV1 as MzGenericLongV1;
26 pub(crate) use super::TimezoneNamesGenericShortV1 as MzGenericShortV1;
27 pub(crate) use super::TimezoneNamesLocationsOverrideV1 as LocationsOverrideV1;
28 pub(crate) use super::TimezoneNamesLocationsRootV1 as LocationsRootV1;
29 pub(crate) use super::TimezoneNamesSpecificLongV1 as MzSpecificLongV1;
30 pub(crate) use super::TimezoneNamesSpecificShortV1 as MzSpecificShortV1;
31 pub(crate) use super::TimezoneNamesStandardLongV1 as MzStandardLongV1;
32 pub(crate) use icu_time::provider::TimezonePeriods as MzPeriod;
33 pub(crate) use icu_time::provider::TimezonePeriodsV1 as MzPeriodV1;
34}
35
36icu_provider::data_marker!(
37 TimezoneNamesEssentialsV1,
39 TimeZoneEssentials<'static>
40);
41icu_provider::data_marker!(
42 TimezoneNamesLocationsOverrideV1,
44 Locations<'static>
45);
46icu_provider::data_marker!(
47 TimezoneNamesLocationsRootV1,
49 Locations<'static>
50);
51icu_provider::data_marker!(
52 TimezoneNamesCitiesOverrideV1,
54 ExemplarCities<'static>
55);
56icu_provider::data_marker!(
57 TimezoneNamesCitiesRootV1,
59 ExemplarCities<'static>
60);
61
62icu_provider::data_marker!(
63 TimezoneNamesGenericLongV1,
67 MetazoneGenericNames<'static>,
68 has_checksum = true
69);
70icu_provider::data_marker!(
71 TimezoneNamesGenericShortV1,
75 MetazoneGenericNames<'static>,
76 has_checksum = true
77);
78icu_provider::data_marker!(
79 TimezoneNamesStandardLongV1,
83 MetazoneGenericNames<'static>,
84 has_checksum = true
85);
86icu_provider::data_marker!(
87 TimezoneNamesSpecificLongV1,
91 MetazoneSpecificNames<'static>,
92 has_checksum = true
93);
94icu_provider::data_marker!(
95 TimezoneNamesSpecificShortV1,
99 MetazoneSpecificNames<'static>,
100 has_checksum = true,
101);
102
103#[derive(PartialEq, Debug, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
113#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
114#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::time_zones))]
115#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
116#[yoke(prove_covariance_manually)]
117pub struct TimeZoneEssentials<'data> {
118 #[cfg_attr(feature = "serde", serde(borrow,))]
120 pub offset_separator: Cow<'data, str>,
121 #[cfg_attr(
123 feature = "serde",
124 serde(
125 borrow,
126 deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::SinglePlaceholder, _>"
127 )
128 )]
129 pub offset_pattern: Cow<'data, SinglePlaceholderPattern>,
130 #[cfg_attr(feature = "serde", serde(borrow))]
132 pub offset_zero: Cow<'data, str>,
133 #[cfg_attr(feature = "serde", serde(borrow))]
135 pub offset_unknown: Cow<'data, str>,
136}
137
138icu_provider::data_struct!(
139 TimeZoneEssentials<'_>,
140 #[cfg(feature = "datagen")]
141);
142
143#[derive(PartialEq, Debug, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
152#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
153#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::time_zones))]
154#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
155#[yoke(prove_covariance_manually)]
156pub struct Locations<'data> {
157 #[cfg_attr(feature = "serde", serde(borrow))]
159 pub locations: ZeroMap<'data, TimeZone, str>,
160 #[cfg_attr(
162 feature = "serde",
163 serde(
164 borrow,
165 deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::SinglePlaceholder, _>"
166 )
167 )]
168 pub pattern_generic: Cow<'data, SinglePlaceholderPattern>,
169 #[cfg_attr(
171 feature = "serde",
172 serde(
173 borrow,
174 deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::SinglePlaceholder, _>"
175 )
176 )]
177 pub pattern_standard: Cow<'data, SinglePlaceholderPattern>,
178 #[cfg_attr(
180 feature = "serde",
181 serde(
182 borrow,
183 deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::SinglePlaceholder, _>"
184 )
185 )]
186 pub pattern_daylight: Cow<'data, SinglePlaceholderPattern>,
187 #[cfg_attr(
189 feature = "serde",
190 serde(
191 borrow,
192 deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::DoublePlaceholder, _>"
193 )
194 )]
195 pub pattern_partial_location: Cow<'data, DoublePlaceholderPattern>,
196}
197
198icu_provider::data_struct!(
199 Locations<'_>,
200 #[cfg(feature = "datagen")]
201);
202
203#[derive(PartialEq, Debug, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
212#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
213#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::time_zones))]
214#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
215#[yoke(prove_covariance_manually)]
216pub struct ExemplarCities<'data> {
217 #[cfg_attr(feature = "serde", serde(borrow))]
220 pub exemplars: ZeroMap<'data, TimeZone, str>,
221}
222
223icu_provider::data_struct!(
224 ExemplarCities<'_>,
225 #[cfg(feature = "datagen")]
226);
227
228#[derive(PartialEq, Debug, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
237#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
238#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::time_zones))]
239#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
240#[yoke(prove_covariance_manually)]
241pub struct MetazoneGenericNames<'data> {
242 #[cfg_attr(feature = "serde", serde(borrow))]
244 pub defaults: ZeroMap<'data, MetazoneId, str>,
245 #[cfg_attr(feature = "serde", serde(borrow))]
247 pub overrides: ZeroMap<'data, TimeZone, str>,
248}
249
250icu_provider::data_struct!(
251 MetazoneGenericNames<'_>,
252 #[cfg(feature = "datagen")]
253);
254
255#[derive(PartialEq, Debug, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
267#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
268#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::time_zones))]
269#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
270#[yoke(prove_covariance_manually)]
271pub struct MetazoneSpecificNames<'data> {
272 #[cfg_attr(feature = "serde", serde(borrow))]
274 pub defaults: ZeroMap<'data, (MetazoneId, TimeZoneVariant), str>,
275 #[cfg_attr(feature = "serde", serde(borrow))]
277 pub overrides: ZeroMap<'data, (TimeZone, TimeZoneVariant), str>,
278 #[cfg_attr(feature = "serde", serde(borrow))]
280 pub use_standard: ZeroVec<'data, MetazoneId>,
281}
282
283icu_provider::data_struct!(
284 MetazoneSpecificNames<'_>,
285 #[cfg(feature = "datagen")]
286);
287
288#[cfg(feature = "serde")]
289pub(crate) mod legacy {
290 use super::*;
291 use icu_time::zone::ZoneNameTimestamp;
292 use zerovec::ule::NichedOption;
293 use zerovec::ZeroMap2d;
294
295 icu_provider::data_marker!(
296 TimezoneMetazonePeriodsV1,
298 MetazonePeriod<'static>,
299 is_singleton = true,
300 has_checksum = true
301 );
302
303 #[derive(PartialEq, Debug, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)]
312 #[cfg_attr(feature = "serde", derive(serde::Deserialize))]
313 #[yoke(prove_covariance_manually)]
314 #[allow(dead_code, reason = "We construct this struct through serde impls")]
315 pub struct MetazonePeriod<'data> {
316 #[cfg_attr(feature = "serde", serde(borrow))]
319 pub list: ZeroMap2d<'data, TimeZone, ZoneNameTimestamp, NichedOption<MetazoneId, 1>>,
320 }
321
322 icu_provider::data_struct!(
323 MetazonePeriod<'_>,
324 #[cfg(feature = "datagen")]
325 );
326
327 #[inline(never)] pub(crate) fn metazone_timezone_compat(
329 provider: &impl BufferProvider,
330 req: DataRequest<'_>,
331 ) -> Result<DataResponse<icu_time::provider::TimezonePeriodsV1>, DataError> {
332 use alloc::vec::Vec;
333 use icu_time::provider::Timestamp24;
334 use icu_time::provider::TimezonePeriods;
335 use zerotrie::ZeroTrieSimpleAscii;
336 use zerovec::ule::vartuple::VarTuple;
337 use zerovec::ule::AsULE;
338 use zerovec::vecs::VarZeroVecOwned;
339
340 let DataResponse::<TimezoneMetazonePeriodsV1> {
341 payload: old_payload,
342 metadata,
343 } = provider.as_deserializing().load(req)?;
344
345 let index = ZeroTrieSimpleAscii::<Vec<u8>>::from_iter(
346 old_payload
347 .get()
348 .list
349 .iter0()
350 .enumerate()
351 .map(|(i, v)| (v.key0().as_str(), i)),
352 )
353 .convert_store();
354
355 let mut list = VarZeroVecOwned::new();
356
357 for ps in old_payload.get().list.iter0() {
358 let mut cursor = ps.into_iter1_copied();
359 let Some((_, mz)) = cursor.next() else {
360 continue; };
362
363 let rest = cursor
364 .map(move |(&t, mz)| (Timestamp24(ZoneNameTimestamp::from_unaligned(t)), 0, mz))
365 .collect::<ZeroVec<_>>();
366
367 let rest = VarTuple {
368 sized: (0, mz),
369 variable: rest.as_slice(),
370 };
371
372 list.push(&rest);
373 }
374
375 Ok(DataResponse {
376 payload: DataPayload::from_owned(TimezonePeriods {
377 index,
378 list: list.into(),
379 offsets: ZeroVec::from(alloc::vec![Default::default()]),
380 }),
381 metadata,
382 })
383 }
384
385 #[test]
386 fn test_metazone_timezone_compat() {
387 use icu_locale::subtags::subtag;
388 use icu_time::ZonedDateTime;
389
390 let converted = metazone_timezone_compat(
391 &icu_provider_blob::BlobDataProvider::try_new_from_static_blob(
392 include_bytes!("../../tests/data/metazone_periods_old.postcard"),
394 )
395 .unwrap(),
396 Default::default(),
397 )
398 .unwrap()
399 .payload;
400
401 let tz = TimeZone(subtag!("aqcas"));
402 for timestamp in [
403 "1970-01-01 00:00Z",
404 "2009-10-17 18:00Z",
405 "2010-03-04 15:00Z",
406 "2011-10-27 18:00Z",
407 "2012-02-21 17:00Z",
408 "2016-10-21 16:00Z",
409 "2018-03-10 17:00Z",
410 "2018-10-06 20:00Z",
411 "2019-03-16 16:00Z",
412 "2019-10-03 19:00Z",
413 "2020-03-07 16:00Z",
414 "2021-03-13 13:00Z",
415 "2022-03-12 13:00Z",
416 "2023-03-08 16:00Z",
417 ] {
418 let t = ZoneNameTimestamp::from_zoned_date_time_iso(
419 ZonedDateTime::try_offset_only_from_str(timestamp, icu_calendar::Iso).unwrap(),
420 );
421
422 assert_eq!(
423 converted
424 .get()
425 .get(tz, t)
426 .unwrap()
427 .1
428 .map(|mz| match mz.id.get() {
429 22 => 21,
431 31 => 30,
432 _ => unreachable!(),
433 }),
434 icu_time::provider::Baked::SINGLETON_TIMEZONE_PERIODS_V1
435 .get(tz, t)
436 .unwrap()
437 .1
438 .map(|mz| mz.id.get()),
439 "{timestamp:?}",
440 );
441 }
442 }
443}