cquiroz / sbt-tzdb

sbt plugin to create custom timezone db files
BSD 3-Clause "New" or "Revised" License
8 stars 13 forks source link

Zone abbreviations not included in generated code #147

Open anitapado opened 2 years ago

anitapado commented 2 years ago

With the following configuration:

    zonesFilter := { (zone: String) => zone == "America/Vancouver" || zone == "UTC" || zone == "GMT" },
    dbVersion := TzdbPlugin.Version("2021e"),
    tzdbPlatform := TzdbPlugin.Platform.Js

The following code is generated:

object tzdb {
  lazy val version: String = "2021e"
  object ameve {
    val America_Vancouver: scala.scalajs.js.Dynamic = js.Dynamic.literal //..... removed
  }
  lazy val fixedZones: scala.scalajs.js.Dynamic = js.Dynamic.literal(("Etc/UTC", 0), ("Etc/GMT", 0))
  lazy val stdZones: scala.scalajs.js.Dynamic = js.Dynamic.literal(("America/Vancouver", ameve.America_Vancouver))
  lazy val zoneLinks: Map[String, String] = Map(("UTC", "Etc/UTC"), ("GMT", "Etc/GMT"))
}

The generated code doesn't contain any zone abbreviations for America/Vancouver (PST, PDT). The same thing happens for other zones such as Europe/Berlin. The result of that is that when formatting a ZonedDateTime on Scala.JS a null is appended in the place where the zone abbreviation should be put.

val fmt = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.FULL).withLocale(Locale.forLanguageTag("en-CA"))
val str = fmt.format(Instant.now().atZone(ZoneId.of("America/Vancouver"))

str is Jan. 23, 2022 12:13:47 p.m. null.

When using ZoneId.of("UTC"), "UTC" is correctly placed at the end.

I'm willing to attempt fixing this, any pointers are appreciated. Do you think it's a problem with the data or rather can be fixed in the code?

cquiroz commented 2 years ago

Hmm interesting. I wonder if we do parse the abbreviation at all. Sounds to me more of a code thing but maybe you can try with previous versions of tzdb to see if it is different

bwbecker commented 7 months ago

I'm running into similar problems with America/Toronto but with some differences. I tested a number of database versions for dbVersion := TzdbPlugin.Version("2017a") through dbVersion := TzdbPlugin.Version("2022a"). They all produced a tzdb object identical (to my eye; didn't run diff) to (I truncated the val America_Toronto to improve readability):

// Auto-generated code from TZDB definitions, don't edit
package zonedb.java

import scala.scalajs.js

object tzdb {
  lazy val version: String = "2022a"
  object ament {
    val America_Toronto: scala.scalajs.js.Dynamic = js.Dynamic.literal(("s", -19052), ("w", -19052), ...
  }
  lazy val fixedZones: scala.scalajs.js.Dynamic = js.Dynamic.literal(("Etc/UTC", 0), ("Etc/GMT", 0))
  lazy val stdZones: scala.scalajs.js.Dynamic = js.Dynamic.literal(("America/Toronto", ament.America_Toronto))
  lazy val zoneLinks: Map[String, String] = Map(("UTC", "Etc/UTC"), ("GMT", "Etc/GMT"))
}

This works for me. Note that this is very similar to what @anitapado reported, above, but with the implication that it did not work.

However, starting with dbVersion := TzdbPlugin.Version("2022e") I get a significant difference:

// Auto-generated code from TZDB definitions, don't edit
package zonedb.java

import scala.scalajs.js

object tzdb {
  lazy val version: String = "2022e"
  lazy val fixedZones: scala.scalajs.js.Dynamic = js.Dynamic.literal(("Etc/UTC", 0), ("Etc/GMT", 0))
  lazy val stdZones: scala.scalajs.js.Dynamic = js.Dynamic.literal()
  lazy val zoneLinks: Map[String, String] = Map(("UTC", "Etc/UTC"), ("GMT", "Etc/GMT"))
}

Note that the nested object ament is missing and the stdZones is different. This does NOT work for me. It's the same for version 2024a.

I did download https://data.iana.org/time-zones/releases/tzdata2022a.tar.gz and 2022e and did some cursory comparisons. I did not notice anything that appeared relevant in the file northamerica. The files zishrink.awk has some differences at about line 220. The comment on the old code that changed was "# Abbreviate rule names". The comment on the new code is "# Record which rule names are used, and generate their abbreviations." I wonder if there's a bug in there. But maybe you read the northamerica file directly and that script isn't even relevant; I don't know.

The essence of my configuration is

val zonesFilterFn = (zone: String) => { zone == "America/Toronto" || zone == "UTC" || zone == "GMT" }

lazy val oat_locales = (project in file("."))
  .enablePlugins(TzdbPlugin, LocalesPlugin, ScalaJSPlugin)
  .settings(
...
    // Timezones
    dbVersion   := TzdbPlugin.Version("2022a"),       // More recent ones don't work for America/Toronto
    zonesFilter := zonesFilterFn,

    // Locales
    localesFilter        := LocalesFilter.Selection("en-001", "en-US", "en-CA"),
    nsFilter             := NumberingSystemFilter.Minimal,
    supportISOCodes      := true,
    supportNumberFormats := true
  )

As shown, for now I'm just using the 2022a version of the database.