Skip to content

Add TimeZoneVariant::Sundown and use it for Morocco #6713

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 62 additions & 11 deletions components/datetime/src/format/time_zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ impl FormatTimeZone for GenericNonLocationFormat {
MissingInputFieldKind::TimeZoneNameTimestamp,
)));
};
let Some(locations) = data_payloads.locations else {
return Ok(Err(FormatTimeZoneError::NamesNotLoaded));
};
let Some(locations_root) = data_payloads.locations_root else {
return Ok(Err(FormatTimeZoneError::NamesNotLoaded));
};
let Some(generic_names) = (match self.0 {
FieldLength::Four => data_payloads.mz_generic_long.as_ref(),
_ => data_payloads.mz_generic_short.as_ref(),
Expand All @@ -126,11 +132,10 @@ impl FormatTimeZone for GenericNonLocationFormat {
return Ok(Err(FormatTimeZoneError::Fallback));
};

if input
.zone_offset
.is_some_and(|o| o != offsets.standard && Some(o) != offsets.daylight)
{
// Not correctly using the metazone
if input.zone_offset.is_some_and(|o| {
o != offsets.standard && Some(o) != offsets.daylight && Some(o) != offsets.sundown
}) {
// Not a correct offset for the zone
return Ok(Err(FormatTimeZoneError::Fallback));
};

Expand All @@ -144,10 +149,20 @@ impl FormatTimeZone for GenericNonLocationFormat {
return Ok(Ok(()));
}

let Some(mz) = mz else {
let Some((mz, golden_offsets)) = mz else {
return Ok(Err(FormatTimeZoneError::Fallback));
};

if offsets.daylight.is_some() && golden_offsets.daylight.is_none()
|| offsets.sundown.is_some() && golden_offsets.sundown.is_none()
{
// The MZ's golden does not use daylight/sundown, but we do (e.g. London, Dublin, Troll,
// Windhoek).
// Because we might be on an offset that no other zone in the metazone ever uses,
// fall back to location format.
return Ok(Err(FormatTimeZoneError::Fallback));
}

let Some(name) = generic_names
.defaults
.get(&mz)
Expand All @@ -156,7 +171,28 @@ impl FormatTimeZone for GenericNonLocationFormat {
return Ok(Err(FormatTimeZoneError::Fallback));
};

sink.write_str(name)?;
if offsets.daylight.is_none() && golden_offsets.daylight.is_some()
|| offsets.sundown.is_none() & &golden_offsets.sundown.is_some()
{
// The MZ's golden uses daylight/sundown but we don't (e.g. Phoenix, Regina, Algiers,
// Brisbane).
// Disambiguate using the location.
// TODO: Use the standard name here
let Some(location) = locations
.locations
.get(&time_zone_id)
.or_else(|| locations_root.locations.get(&time_zone_id))
else {
return Ok(Err(FormatTimeZoneError::Fallback));
};

locations
.pattern_partial_location
.interpolate([location, name])
.write_to(sink)?;
} else {
name.write_to(sink)?;
}

Ok(Ok(()))
}
Expand Down Expand Up @@ -208,8 +244,10 @@ impl FormatTimeZone for SpecificNonLocationFormat {
TimeZoneVariant::Standard
} else if Some(offset) == offsets.daylight {
TimeZoneVariant::Daylight
} else if Some(offset) == offsets.sundown {
TimeZoneVariant::Sundown
} else {
// Not correctly using the metazone
// Not a correct offset for the zone
return Ok(Err(FormatTimeZoneError::Fallback));
};

Expand All @@ -219,7 +257,20 @@ impl FormatTimeZone for SpecificNonLocationFormat {
return Ok(Ok(()));
}

let Some(mz) = mz else {
let Some((mz, golden_offsets)) = mz else {
return Ok(Err(FormatTimeZoneError::Fallback));
};

// Metazone names are defined for the offsets of the golden zone,
// so recalculate the variant just in case.
let variant = if offset == golden_offsets.standard {
TimeZoneVariant::Standard
} else if Some(offset) == golden_offsets.daylight {
TimeZoneVariant::Daylight
} else if Some(offset) == golden_offsets.sundown {
TimeZoneVariant::Sundown
} else {
// Not a correct offset for the metazone
return Ok(Err(FormatTimeZoneError::Fallback));
};

Expand Down Expand Up @@ -380,7 +431,7 @@ impl FormatTimeZone for GenericLocationFormat {
input.zone_name_timestamp,
) {
if let Some((os, _)) = mz_periods.get(time_zone_id, timestamp) {
if offset != os.standard && Some(offset) != os.daylight {
if offset != os.standard && Some(offset) != os.daylight && Some(offset) != os.sundown {
return Ok(Err(FormatTimeZoneError::Fallback));
};
}
Expand Down Expand Up @@ -566,7 +617,7 @@ impl FormatTimeZone for GenericPartialLocationFormat {
let Some(non_location) = non_locations.overrides.get(&time_zone_id).or_else(|| {
non_locations
.defaults
.get(&metazone_period.get(time_zone_id, timestamp)?.1?)
.get(&metazone_period.get(time_zone_id, timestamp)?.1?.0)
}) else {
return Ok(Err(FormatTimeZoneError::Fallback));
};
Expand Down
42 changes: 18 additions & 24 deletions components/datetime/src/pattern/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1863,16 +1863,16 @@ impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
/// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
/// use writeable::assert_try_writeable_eq;
///
/// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
/// "2024-01-01T00:00:00+00:00[Europe/London]",
/// let mut zone_berlin_winter = ZonedDateTime::try_full_from_str(
/// "2024-01-01T00:00:00+01:00[Europe/Berlin]",
/// Gregorian,
/// IanaParser::new(),
/// VariantOffsetsCalculator::new(),
/// )
/// .unwrap()
/// .zone;
/// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
/// "2024-07-01T00:00:00+01:00[Europe/London]",
/// let mut zone_berlin_summer = ZonedDateTime::try_full_from_str(
/// "2024-07-01T00:00:00+02:00[Europe/Berlin]",
/// Gregorian,
/// IanaParser::new(),
/// VariantOffsetsCalculator::new(),
Expand All @@ -1888,6 +1888,7 @@ impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
///
/// names.include_time_zone_essentials().unwrap();
/// names.include_time_zone_generic_long_names().unwrap();
/// names.include_time_zone_location_names().unwrap();
///
/// // Create a pattern with symbol `vvvv`:
/// let pattern_str = "'Your time zone is:' vvvv";
Expand All @@ -1896,18 +1897,14 @@ impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
/// assert_try_writeable_eq!(
/// names
/// .with_pattern_unchecked(&pattern)
/// .format(&zone_london_winter),
/// "Your time zone is: Greenwich Mean Time",
/// .format(&zone_berlin_winter),
/// "Your time zone is: Central European Time",
/// );
/// assert_try_writeable_eq!(
/// names
/// .with_pattern_unchecked(&pattern)
/// .format(&zone_london_summer),
/// // Note: The year-round generic name of this zone is Greenwich
/// // Mean Time, which may be confusing since the zone observes
/// // daylight savings time. See:
/// // <https://unicode-org.atlassian.net/issues/CLDR-18378>
/// "Your time zone is: Greenwich Mean Time",
/// .format(&zone_berlin_summer),
/// "Your time zone is: Central European Time",
/// );
/// ```
#[cfg(feature = "compiled_data")]
Expand Down Expand Up @@ -1955,16 +1952,16 @@ impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
/// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
/// use writeable::assert_try_writeable_eq;
///
/// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
/// "2024-01-01T00:00:00+00:00[Europe/London]",
/// let mut zone_berlin_winter = ZonedDateTime::try_full_from_str(
/// "2024-01-01T00:00:00+01:00[Europe/Berlin]",
/// Gregorian,
/// IanaParser::new(),
/// VariantOffsetsCalculator::new(),
/// )
/// .unwrap()
/// .zone;
/// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
/// "2024-07-01T00:00:00+01:00[Europe/London]",
/// let mut zone_berlin_summer = ZonedDateTime::try_full_from_str(
/// "2024-07-01T00:00:00+02:00[Europe/Berlin]",
/// Gregorian,
/// IanaParser::new(),
/// VariantOffsetsCalculator::new(),
Expand All @@ -1980,6 +1977,7 @@ impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
///
/// names.include_time_zone_essentials().unwrap();
/// names.include_time_zone_generic_short_names().unwrap();
/// names.include_time_zone_location_names().unwrap();
///
/// // Create a pattern with symbol `v`:
/// let pattern_str = "'Your time zone is:' v";
Expand All @@ -1988,18 +1986,14 @@ impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
/// assert_try_writeable_eq!(
/// names
/// .with_pattern_unchecked(&pattern)
/// .format(&zone_london_winter),
/// "Your time zone is: GMT",
/// .format(&zone_berlin_winter),
/// "Your time zone is: CET",
/// );
/// assert_try_writeable_eq!(
/// names
/// .with_pattern_unchecked(&pattern)
/// .format(&zone_london_summer),
/// // Note: The year-round generic name of this zone is Greenwich
/// // Mean Time, which may be confusing since the zone observes
/// // daylight savings time. See:
/// // <https://unicode-org.atlassian.net/issues/CLDR-18378>
/// "Your time zone is: GMT",
/// .format(&zone_berlin_summer),
/// "Your time zone is: CET",
/// );
/// ```
#[cfg(feature = "compiled_data")]
Expand Down
11 changes: 9 additions & 2 deletions components/datetime/src/provider/time_zones.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ pub(crate) mod legacy {
index,
list: list.into(),
offsets: ZeroVec::from(alloc::vec![Default::default()]),
goldens: Default::default(),
}),
metadata,
})
Expand Down Expand Up @@ -424,11 +425,17 @@ pub(crate) mod legacy {
);

assert_eq!(
converted.get().get(tz, t).unwrap().1,
converted
.get()
.get(tz, t)
.unwrap()
.1
.map(|(mz, _golden_os)| mz),
icu_time::provider::Baked::SINGLETON_TIMEZONE_PERIODS_V1
.get(tz, t)
.unwrap()
.1,
.1
.map(|(mz, _golden_os)| mz),
"{timestamp:?}",
);
}
Expand Down
77 changes: 69 additions & 8 deletions components/datetime/tests/patterns/tests/time_zones.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,59 @@
"XXXXX": "-07:00"
}
},
{
"locale": "fr",
"datetime": "2021-07-11T12:00:00.000+01:00[Africa/Algiers]",
"expectations": {
"z": "UTC+1",
"zzzz": "heure normale d’Europe centrale",

"v": "heure : Algérie",
"vvvv": "heure d’Europe centrale (Algérie)"
}
},
{
"locale": "en-GB",
"datetime": "2021-07-11T12:00:00.000+01[Africa/Casablanca]",
"expectations": {
"z": "CET",
"zzzz": "Central European Standard Time",

"v": "Morocco Time",
"vvvv": "Morocco Time"
}
},
{
"locale": "en-GB",
"datetime": "2021-07-11T12:00:00.000+00[Africa/Casablanca]",
"expectations": {
"z": "GMT+0",
"zzzz": "GMT+00:00",

"v": "Morocco Time",
"vvvv": "Morocco Time"
}
},
{
"locale": "en",
"datetime": "2021-07-11T12:00:00.000-06:00[America/Regina]",
"expectations": {
"z": "CST",
"zzzz": "Central Standard Time",

"v": "CT (Regina)",
"vvvv": "Central Time (Regina)"
}
},
{
"locale": "en",
"datetime": "2021-07-11T12:00:00.000+01:00[Europe/London]",
"expectations": {
"z": "GMT+1",
"zzzz": "British Summer Time",

"v": "GMT",
"vvvv": "Greenwich Mean Time",
"v": "UK Time",
"vvvv": "UK Time",

"VVV": "London",
"VVVV": "UK Time",
Expand All @@ -48,15 +92,32 @@
"OOOO": "GMT+01:00"
}
},
{
"locale": "en",
"datetime": "2021-07-11T12:00:00.000+00:00[Europe/London]",
"expectations": {
"z": "GMT",
"zzzz": "Greenwich Mean Time",

"v": "UK Time",
"vvvv": "UK Time",

"VVV": "London",
"VVVV": "UK Time",

"O": "GMT+0",
"OOOO": "GMT+00:00"
}
},
{
"locale": "en",
"datetime": "2021-07-11T12:00:00.000+01:00[Europe/Dublin]",
"expectations": {
"z": "GMT+1",
"zzzz": "Irish Standard Time",

"v": "GMT",
"vvvv": "Greenwich Mean Time",
"v": "Ireland Time",
"vvvv": "Ireland Time",

"VVV": "Dublin",
"VVVV": "Ireland Time",
Expand Down Expand Up @@ -90,7 +151,7 @@
"zzzz": "Среднее время по Гринвичу",

"v": "Тролль",
"vvvv": "Среднее время по Гринвичу",
"vvvv": "Тролль",

"VVV": "Тролль",
"VVVV": "Тролль",
Expand Down Expand Up @@ -182,16 +243,16 @@
"locale": "en",
"datetime": "2013-08-15T12:00:00+01[Africa/Windhoek]",
"expectations": {
"vvvv": "West Africa Time",
"vvvv": "Namibia Time",
"zzzz": "West Africa Standard Time"
}
},
{
"locale": "en",
"datetime": "2013-09-15T12:00:00+02[Africa/Windhoek]",
"expectations": {
"vvvv": "West Africa Time",
"zzzz": "West Africa Summer Time"
"vvvv": "Namibia Time",
"zzzz": "Namibia Daylight Time"
}
},
{
Expand Down
Loading
Loading