Skip to content

Commit

Permalink
Use pattern in TimeZoneEssentialsV1 (#5637)
Browse files Browse the repository at this point in the history
  • Loading branch information
robertbastian authored Oct 2, 2024
1 parent 11ff589 commit cc8d36e
Show file tree
Hide file tree
Showing 52 changed files with 1,347 additions and 2,417 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions components/datetime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fixed_decimal = { workspace = true }
icu_calendar = { workspace = true }
icu_decimal = { workspace = true }
icu_locale_core = { workspace = true }
icu_pattern = { workspace = true, features = ["zerovec", "alloc"] }
icu_plurals = { workspace = true }
icu_provider = { workspace = true, features = ["macros"] }
icu_timezone = { workspace = true }
Expand Down Expand Up @@ -74,6 +75,7 @@ serde = [
"dep:serde",
"icu_calendar/serde",
"icu_decimal/serde",
"icu_pattern/serde",
"icu_plurals/serde",
"icu_provider/serde",
"icu_timezone/serde",
Expand All @@ -87,6 +89,7 @@ datagen = [
"dep:databake",
"dep:litemap",
"icu_calendar/datagen",
"icu_pattern/databake",
"icu_plurals/datagen",
"icu_timezone/datagen",
"serde",
Expand Down
4 changes: 2 additions & 2 deletions components/datetime/src/provider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const _: () = {
impl_metazone_generic_names_short_v1_marker!(Baked);
impl_metazone_specific_names_long_v1_marker!(Baked);
impl_metazone_specific_names_short_v1_marker!(Baked);
impl_time_zone_formats_v1_marker!(Baked);
impl_time_zone_essentials_v1_marker!(Baked);

impl_weekday_names_v1_marker!(Baked);
impl_day_period_names_v1_marker!(Baked);
Expand Down Expand Up @@ -109,7 +109,7 @@ pub const MARKERS: &[DataMarkerInfo] = &[
time_zones::MetazoneGenericNamesShortV1Marker::INFO,
time_zones::MetazoneSpecificNamesLongV1Marker::INFO,
time_zones::MetazoneSpecificNamesShortV1Marker::INFO,
time_zones::TimeZoneFormatsV1Marker::INFO,
time_zones::TimeZoneEssentialsV1Marker::INFO,
neo::WeekdayNamesV1Marker::INFO,
neo::DayPeriodNamesV1Marker::INFO,
neo::GluePatternV1Marker::INFO,
Expand Down
69 changes: 51 additions & 18 deletions components/datetime/src/provider/time_zones.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
//! Data provider structs for time zones.
use alloc::borrow::Cow;
use icu_pattern::{DoublePlaceholderPattern, SinglePlaceholderPattern};
use icu_provider::prelude::*;
use tinystr::TinyStr8;
use zerovec::{ZeroMap, ZeroMap2d};

pub use icu_timezone::provider::{MetazoneId, TimeZoneBcp47Id};
Expand All @@ -22,26 +22,26 @@ pub(crate) mod tz {
pub(crate) use super::MetazoneSpecificNamesLongV1Marker as MzSpecificLongV1Marker;
pub(crate) use super::MetazoneSpecificNamesShortV1Marker as MzSpecificShortV1Marker;
pub(crate) use super::MetazoneSpecificNamesV1 as MzSpecificV1;
pub(crate) use super::TimeZoneFormatsV1 as EssentialsV1;
pub(crate) use super::TimeZoneFormatsV1Marker as EssentialsV1Marker;
pub(crate) use super::TimeZoneEssentialsV1 as EssentialsV1;
pub(crate) use super::TimeZoneEssentialsV1Marker as EssentialsV1Marker;
}

/// An ICU4X mapping to the CLDR timeZoneNames format strings.
/// See CLDR-JSON timeZoneNames.json for more context.
/// See CLDR-JSON timeZoneNames.json and <https://cldr.unicode.org/translation/time-zones-and-city-names>
/// for more context.
///
/// <div class="stab unstable">
/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways,
/// including in SemVer minor releases. While the serde representation of data structs is guaranteed
/// to be stable, their Rust representation might not be. Use with caution.
/// </div>
#[icu_provider::data_struct(TimeZoneFormatsV1Marker = "time_zone/formats@1")]
#[icu_provider::data_struct(TimeZoneEssentialsV1Marker = "time_zone/essentials@1")]
#[derive(PartialEq, Debug, Clone, Default)]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::time_zones))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[yoke(prove_covariance_manually)]
// TODO: Consider renaming to "TimeZoneEssentialsV1"
pub struct TimeZoneFormatsV1<'data> {
pub struct TimeZoneEssentialsV1<'data> {
/// The hour format for displaying offsets.
#[cfg_attr(feature = "serde", serde(borrow))]
#[cfg_attr(
Expand All @@ -50,23 +50,56 @@ pub struct TimeZoneFormatsV1<'data> {
)]
pub hour_format: (Cow<'data, str>, Cow<'data, str>),
/// The localized offset format.
#[cfg_attr(feature = "serde", serde(borrow))]
pub offset_format: Cow<'data, str>,
#[cfg_attr(
feature = "serde",
serde(
borrow,
deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::SinglePlaceholder, _>"
)
)]
pub offset_format: Cow<'data, SinglePlaceholderPattern>,
/// The localized zero-offset format.
#[cfg_attr(feature = "serde", serde(borrow))]
pub offset_zero_format: Cow<'data, str>,
/// The format string for a region.
#[cfg_attr(feature = "serde", serde(borrow))]
pub region_format: Cow<'data, str>,
/// The format strings for region format variants
/// e.g. daylight, standard.
#[cfg_attr(
feature = "serde",
serde(
borrow,
deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::SinglePlaceholder, _>"
)
)]
pub region_format: Cow<'data, SinglePlaceholderPattern>,
/// The format string for a region's standard time.
// CURRENLY UNUSED
#[cfg_attr(feature = "serde", serde(borrow))]
pub region_format_variants: ZeroMap<'data, TinyStr8, str>,
/// The format string to fall back to if data is unavailable.
#[cfg_attr(
feature = "serde",
serde(
borrow,
deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::SinglePlaceholder, _>"
)
)]
pub region_format_st: Cow<'data, SinglePlaceholderPattern>,
/// The format string for a region's daylight time.
// CURRENLY UNUSED
#[cfg_attr(feature = "serde", serde(borrow))]
pub fallback_format: Cow<'data, str>,
#[cfg_attr(
feature = "serde",
serde(
borrow,
deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::SinglePlaceholder, _>"
)
)]
pub region_format_dt: Cow<'data, SinglePlaceholderPattern>,
/// Metazone Name with Location Pattern.
// CURRENLY UNUSED
#[cfg_attr(
feature = "serde",
serde(
borrow,
deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::DoublePlaceholder, _>"
)
)]
pub fallback_format: Cow<'data, DoublePlaceholderPattern>,
}

/// An ICU4X mapping to the CLDR timeZoneNames exemplar cities.
Expand Down
96 changes: 47 additions & 49 deletions components/datetime/src/time_zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ use crate::{
provider,
};
use alloc::borrow::Cow;
use alloc::string::String;
use core::fmt;
use icu_timezone::TimeZoneBcp47Id;
use icu_timezone::UtcOffset;
use tinystr::tinystr;
use writeable::{adapters::CoreWriteAsPartsWrite, Writeable};
use writeable::Writeable;

/// All time zone styles that this crate can format
#[derive(Debug, Copy, Clone)]
Expand Down Expand Up @@ -57,7 +56,7 @@ impl ResolvedNeoTimeZoneSkeleton {
#[derive(Debug, Copy, Clone)]
pub(crate) struct TimeZoneDataPayloadsBorrowed<'a> {
/// The data that contains meta information about how to display content.
pub(crate) zone_formats: Option<&'a provider::time_zones::TimeZoneFormatsV1<'a>>,
pub(crate) zone_formats: Option<&'a provider::time_zones::TimeZoneEssentialsV1<'a>>,
/// The exemplar cities for time zones.
pub(crate) exemplar_cities: Option<&'a provider::time_zones::ExemplarCitiesV1<'a>>,
/// The generic long metazone names, e.g. Pacific Time
Expand Down Expand Up @@ -500,45 +499,40 @@ impl FormatTimeZoneWithFallback for LocalizedOffsetFormat {
sink.write_str(&zone_formats.offset_zero_format)?;
Ok(())
} else {
// TODO(blocked on #277) Use formatter utility instead of replacing "{0}".
let mut scratch = String::new();
sink.write_str(
&zone_formats
.offset_format
.replace(
"{0}",
if offset.is_positive() {
&zone_formats.hour_format.0
} else {
&zone_formats.hour_format.1
},
)
// support all combos of "(HH|H):mm" by replacing longest patterns first.
.replace("HH", {
scratch.clear();
let _infallible = format_offset_hours(
&mut CoreWriteAsPartsWrite(&mut scratch),
offset,
ZeroPadding::On,
);
&scratch
})
.replace("mm", {
scratch.clear();
let _infallible =
format_offset_minutes(&mut CoreWriteAsPartsWrite(&mut scratch), offset);
&scratch
})
.replace('H', {
scratch.clear();
let _infallible = format_offset_hours(
&mut CoreWriteAsPartsWrite(&mut scratch),
offset,
ZeroPadding::Off,
);
&scratch
}),
)?;
struct FormattedHour<'a> {
format_str: &'a str,
offset: UtcOffset,
}

impl Writeable for FormattedHour<'_> {
fn write_to_parts<S: writeable::PartsWrite + ?Sized>(
&self,
sink: &mut S,
) -> fmt::Result {
for c in self.format_str.chars() {
match c {
'H' => format_offset_hours(sink, self.offset, ZeroPadding::On)?,
'h' => format_offset_hours(sink, self.offset, ZeroPadding::Off)?,
'm' => format_offset_minutes(sink, self.offset)?,
c => sink.write_char(c)?,
}
}
Ok(())
}
}

zone_formats
.offset_format
.interpolate([FormattedHour {
format_str: if offset.is_positive() {
&zone_formats.hour_format.0
} else {
&zone_formats.hour_format.1
},
offset,
}])
.write_to(sink)?;

Ok(())
})
}
Expand Down Expand Up @@ -574,16 +568,20 @@ impl FormatTimeZone for GenericLocationFormat {
let Some(zone_formats) = data_payloads.zone_formats else {
return Ok(Err(FormatTimeZoneError::MissingZoneSymbols));
};
// TODO(blocked on #277) Use formatter utility instead of replacing "{0}".
let formatted_time_zone: Option<alloc::string::String> = data_payloads
let Some(location) = data_payloads
.exemplar_cities
.as_ref()
.and_then(|cities| input.time_zone_id.and_then(|id| cities.0.get(&id)))
.map(|location| zone_formats.region_format.replace("{0}", location));
Ok(match formatted_time_zone {
Some(ftz) => Ok(sink.write_str(&ftz)?),
None => Err(FormatTimeZoneError::NameNotFound),
})
else {
return Ok(Err(FormatTimeZoneError::NameNotFound));
};

zone_formats
.region_format
.interpolate([location])
.write_to(sink)?;

Ok(Ok(()))
}
}

Expand Down
6 changes: 3 additions & 3 deletions provider/data/datetime/data/mod.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions provider/data/datetime/data/time_zone_essentials_v1_marker.rs.data

Large diffs are not rendered by default.

Loading

0 comments on commit cc8d36e

Please sign in to comment.