Skip to content

Commit

Permalink
Embrace Etc/Unknown timezone (#5656)
Browse files Browse the repository at this point in the history
  • Loading branch information
robertbastian authored Oct 15, 2024
1 parent 5afeaf3 commit e1bc5b4
Show file tree
Hide file tree
Showing 45 changed files with 900 additions and 704 deletions.
2 changes: 1 addition & 1 deletion components/datetime/src/neo_marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@
//!
//! // "uschi" - has metazone symbol data for generic_non_location_short
//! let mut time_zone = "-0600".parse::<CustomTimeZone>().unwrap();
//! time_zone.time_zone_id = mapper.as_borrowed().iana_to_bcp47("America/Chicago").unwrap();
//! time_zone.time_zone_id = mapper.as_borrowed().iana_to_bcp47("America/Chicago");
//! time_zone.maybe_calculate_metazone(&mzc, &datetime);
//! assert_try_writeable_eq!(
//! tzf.format(&time_zone),
Expand Down
3 changes: 3 additions & 0 deletions components/datetime/src/provider/time_zones.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ pub struct LocationsV1<'data> {
/// Per-zone location display name
#[cfg_attr(feature = "serde", serde(borrow))]
pub locations: ZeroMap<'data, TimeZoneBcp47Id, str>,
/// The display name for an unknown time zone. This is not combined with a pattern.
#[cfg_attr(feature = "serde", serde(borrow))]
pub unknown: Cow<'data, str>,
/// The format string for a region's generic time.
#[cfg_attr(
feature = "serde",
Expand Down
63 changes: 22 additions & 41 deletions components/datetime/src/time_zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,20 +524,14 @@ impl FormatTimeZone for GenericLocationFormat {
return Ok(Err(FormatTimeZoneError::MissingZoneSymbols));
};

let location = locations
.locations
.get(&time_zone_id)
.or_else(|| {
locations
.locations
.get(&TimeZoneBcp47Id(tinystr::tinystr!(8, "unk")))
})
.unwrap_or("Unknown");

locations
.pattern_generic
.interpolate([location])
.write_to(sink)?;
if let Some(location) = locations.locations.get(&time_zone_id) {
locations
.pattern_generic
.interpolate([location])
.write_to(sink)?;
} else {
sink.write_str(&locations.unknown)?;
}

Ok(Ok(()))
}
Expand Down Expand Up @@ -567,34 +561,21 @@ impl FormatTimeZone for SpecificLocationFormat {
return Ok(Err(FormatTimeZoneError::MissingZoneSymbols));
};

let Some(location) = locations.locations.get(&time_zone_id) else {
return Ok(Err(FormatTimeZoneError::Fallback));
};

Ok(if zone_variant == ZoneVariant::daylight() {
locations
.pattern_daylight
.interpolate([location])
.write_to(sink)?;

Ok(())
} else if zone_variant == ZoneVariant::standard() {
locations
.pattern_standard
.interpolate([location])
.write_to(sink)?;

Ok(())
if let Some(location) = locations.locations.get(&time_zone_id) {
if zone_variant == ZoneVariant::daylight() {
&locations.pattern_daylight
} else if zone_variant == ZoneVariant::standard() {
&locations.pattern_standard
} else {
&locations.pattern_generic
}
.interpolate([location])
.write_to(sink)?;
} else {
sink.with_part(writeable::Part::ERROR, |sink| {
locations
.pattern_generic
.interpolate([location])
.write_to(sink)
})?;

Err(FormatTimeZoneError::MissingInputField("zone_offset"))
})
sink.write_str(&locations.unknown)?;
}

Ok(Ok(()))
}
}

Expand Down
2 changes: 1 addition & 1 deletion components/timezone/README.md

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

24 changes: 17 additions & 7 deletions components/timezone/src/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,27 @@ use crate::{
/// // The IANA zone "Australia/Melbourne" is the BCP-47 zone "aumel":
/// assert_eq!(
/// mapper.iana_to_bcp47("Australia/Melbourne"),
/// Some(TimeZoneBcp47Id(tinystr!(8, "aumel")))
/// TimeZoneBcp47Id(tinystr!(8, "aumel"))
/// );
///
/// // Lookup is ASCII-case-insensitive:
/// assert_eq!(
/// mapper.iana_to_bcp47("australia/melbourne"),
/// Some(TimeZoneBcp47Id(tinystr!(8, "aumel")))
/// TimeZoneBcp47Id(tinystr!(8, "aumel"))
/// );
///
/// // The IANA zone "Australia/Victoria" is an alias:
/// assert_eq!(
/// mapper.iana_to_bcp47("Australia/Victoria"),
/// Some(TimeZoneBcp47Id(tinystr!(8, "aumel")))
/// TimeZoneBcp47Id(tinystr!(8, "aumel"))
/// );
///
/// // The IANA zone "Australia/Boing_Boing" does not exist
/// // (maybe not *yet*), so it produces the special unknown
/// // timezone in order for this operation to be infallible:
/// assert_eq!(
/// mapper.iana_to_bcp47("Australia/Boing_Boing"),
/// TimeZoneBcp47Id::unknown()
/// );
///
/// // We can recover the canonical identifier from the mapper:
Expand Down Expand Up @@ -175,22 +183,24 @@ impl TimeZoneIdMapperBorrowed<'_> {
/// let mapper = TimeZoneIdMapper::new();
/// let mapper = mapper.as_borrowed();
///
/// let result = mapper.iana_to_bcp47("Asia/CALCUTTA").unwrap();
/// let result = mapper.iana_to_bcp47("Asia/CALCUTTA");
///
/// assert_eq!(*result, "inccu");
///
/// // Unknown IANA time zone ID:
/// assert_eq!(mapper.iana_to_bcp47("America/San_Francisco"), None);
/// assert_eq!(mapper.iana_to_bcp47("America/San_Francisco"), TimeZoneBcp47Id::unknown());
/// ```
pub fn iana_to_bcp47(&self, iana_id: &str) -> Option<TimeZoneBcp47Id> {
pub fn iana_to_bcp47(&self, iana_id: &str) -> TimeZoneBcp47Id {
self.iana_lookup_quick(iana_id)
.and_then(|trie_value| self.data.bcp47_ids.get(trie_value.index()))
.unwrap_or(TimeZoneBcp47Id::unknown())
}

/// Same as [`Self::iana_to_bcp47()`] but works with potentially ill-formed UTF-8.
pub fn iana_bytes_to_bcp47(&self, iana_id: &[u8]) -> Option<TimeZoneBcp47Id> {
pub fn iana_bytes_to_bcp47(&self, iana_id: &[u8]) -> TimeZoneBcp47Id {
self.iana_lookup_quick(iana_id)
.and_then(|trie_value| self.data.bcp47_ids.get(trie_value.index()))
.unwrap_or(TimeZoneBcp47Id::unknown())
}

/// Normalizes the syntax of an IANA time zone ID.
Expand Down
9 changes: 3 additions & 6 deletions components/timezone/src/ixdtf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

use crate::{
CustomTimeZone, CustomZonedDateTime, InvalidOffsetError, MetazoneCalculator, TimeZoneBcp47Id,
TimeZoneIdMapper, UtcOffset, ZoneOffsetCalculator,
CustomTimeZone, CustomZonedDateTime, InvalidOffsetError, MetazoneCalculator, TimeZoneIdMapper,
UtcOffset, ZoneOffsetCalculator,
};
use alloc::str::FromStr;
use icu_calendar::{AnyCalendar, Date, DateError, DateTime, Iso, RangeError, Time};
Expand Down Expand Up @@ -127,10 +127,7 @@ impl CustomTimeZone {
match record {
TimeZoneRecord::Name(iana_identifier) => {
let mapper = TimeZoneIdMapper::new();
let time_zone_id = mapper
.as_borrowed()
.iana_bytes_to_bcp47(iana_identifier)
.unwrap_or(TimeZoneBcp47Id::unknown());
let time_zone_id = mapper.as_borrowed().iana_bytes_to_bcp47(iana_identifier);

let mut tz = Self {
time_zone_id,
Expand Down
2 changes: 1 addition & 1 deletion components/timezone/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
//! let mut time_zone = CustomTimeZone::new_with_offset("-0600".parse().unwrap());
//! let mapper = TimeZoneIdMapper::new();
//! time_zone.time_zone_id =
//! mapper.as_borrowed().iana_to_bcp47("America/Chicago").unwrap_or(TimeZoneBcp47Id::unknown());
//! mapper.as_borrowed().iana_to_bcp47("America/Chicago");
//!
//! // Alternatively, set it directly from the BCP-47 ID
//! assert_eq!(time_zone.time_zone_id, TimeZoneBcp47Id(tinystr!(8, "uschi")));
Expand Down
14 changes: 5 additions & 9 deletions components/timezone/src/time_zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,12 @@ impl CustomTimeZone {
};
}
let mapper = TimeZoneIdMapper::new();
if let Some(time_zone_id) = mapper.as_borrowed().iana_bytes_to_bcp47(code_units) {
return Self {
offset: None,
time_zone_id,
metazone_id: None,
zone_variant: None,
};
Self {
offset: None,
time_zone_id: mapper.as_borrowed().iana_bytes_to_bcp47(code_units),
metazone_id: None,
zone_variant: None,
}

Self::unknown()
}

/// Infer the metazone ID.
Expand Down
3 changes: 1 addition & 2 deletions ffi/capi/bindings/c/TimeZoneIdMapper.h

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

2 changes: 1 addition & 1 deletion ffi/capi/bindings/cpp/icu4x/TimeZoneIdMapper.d.hpp

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

9 changes: 4 additions & 5 deletions ffi/capi/bindings/cpp/icu4x/TimeZoneIdMapper.hpp

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

11 changes: 4 additions & 7 deletions ffi/capi/bindings/dart/TimeZoneIdMapper.g.dart

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

2 changes: 1 addition & 1 deletion ffi/capi/bindings/js/TimeZoneIdMapper.d.ts

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

5 changes: 2 additions & 3 deletions ffi/capi/bindings/js/TimeZoneIdMapper.mjs

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

6 changes: 1 addition & 5 deletions ffi/capi/src/timezone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,7 @@ pub mod ffi {
mapper: &crate::timezone_mapper::ffi::TimeZoneIdMapper,
id: &DiplomatStr,
) {
self.0.time_zone_id = mapper
.0
.as_borrowed()
.iana_bytes_to_bcp47(id)
.unwrap_or(TimeZoneBcp47Id::unknown());
self.0.time_zone_id = mapper.0.as_borrowed().iana_bytes_to_bcp47(id);
}

/// Writes the value of the `time_zone_id` field as a string.
Expand Down
5 changes: 2 additions & 3 deletions ffi/capi/src/timezone_mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,10 @@ pub mod ffi {
&self,
value: &DiplomatStr,
write: &mut diplomat_runtime::DiplomatWrite,
) -> Option<()> {
) {
let handle = self.0.as_borrowed();
let bcp47 = handle.iana_bytes_to_bcp47(value)?;
let bcp47 = handle.iana_bytes_to_bcp47(value);
let _infallible = bcp47.0.write_to(write);
Some(())
}

#[diplomat::rust_link(icu::timezone::TimeZoneIdMapperBorrowed::normalize_iana, FnInStruct)]
Expand Down
Loading

0 comments on commit e1bc5b4

Please sign in to comment.