fix(timezone): show the IANA id + abbreviation, not the long localized name
"Central European Time (Europe/Berlin)" is too wide — it made the zone
field wrap and stretch. Lead with the id ("Europe/Berlin") and follow it
with the abbreviation instead: "CEST · GMT+02:00" in the picker and edit
card, "CET · 8:00 AM – 9:00 AM" on the detail card (abbreviation + the
event's own-zone time).
The abbreviation is resolved DST-aware at the same instant as the offset
(CET vs CEST) via "zzz"; zones with no named abbreviation fall back to a
"GMT+05:30" form, and zoneDescriptor drops the separate offset in that
case so it isn't stated twice. The long localized name is kept on the
option for search only — typing "pacific" still works — but no longer
shown.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,45 @@ class TimeZoneCatalogTest {
|
||||
assertThat(ny.region).isEqualTo("America")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `label is the id with underscores undone`() {
|
||||
assertThat(zones.first { it.id == "America/New_York" }.label)
|
||||
.isEqualTo("America/New York")
|
||||
assertThat(zones.first { it.id == "Europe/Berlin" }.label).isEqualTo("Europe/Berlin")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `resolved abbreviation is compact, not the long name`() {
|
||||
// Whatever CLDR gives ("CET"/"CEST" or a "GMT+.." fallback), it must be
|
||||
// short and space-free — that's the whole point of showing it instead of
|
||||
// "Central European Time".
|
||||
val berlin = zones.first { it.id == "Europe/Berlin" }
|
||||
assertThat(berlin.shortName).doesNotContain(" ")
|
||||
assertThat(berlin.shortName.length).isLessThan(berlin.displayName.length)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `descriptor pairs a named abbreviation with the offset`() {
|
||||
val option = TimeZoneOption(
|
||||
id = "Europe/Berlin",
|
||||
displayName = "Central European Time",
|
||||
shortName = "CET",
|
||||
offsetMinutes = 60,
|
||||
)
|
||||
assertThat(zoneDescriptor(option)).isEqualTo("CET · GMT+01:00")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `descriptor drops the offset when the abbreviation already is one`() {
|
||||
// Repeating the offset after an offset-shaped abbreviation would just say
|
||||
// the same thing twice.
|
||||
fun descriptorFor(shortName: String, offset: Int) = zoneDescriptor(
|
||||
TimeZoneOption(id = "X/Y", displayName = "", shortName = shortName, offsetMinutes = offset),
|
||||
)
|
||||
assertThat(descriptorFor("UTC", 0)).isEqualTo("UTC")
|
||||
assertThat(descriptorFor("GMT+05:30", 330)).isEqualTo("GMT+05:30")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `offset is resolved at the given instant, not the current one`() {
|
||||
val berlin = zones.first { it.id == "Europe/Berlin" }
|
||||
|
||||
Reference in New Issue
Block a user