Localize.DateTime.Timezone (Localize v1.4.0)

Copy Markdown View Source

Provides timezone data access and timezone formatting for CLDR date/time format symbols.

This module combines CLDR short zone code lookups (mapping between BCP 47 timezone identifiers and IANA timezone names) with the format symbol handlers for z, Z, O, v, V, X, and x.

Summary

Functions

Returns the exemplar city for an IANA timezone identifier.

Returns {:ok, map} for a given CLDR short zone code, or :error if no such short code exists.

Returns the generic location format for a timezone.

Returns a timezone map for a given CLDR short zone code, or a default value.

Returns the localized GMT offset format.

Returns the ISO 8601 timezone offset format.

Returns the canonical IANA time zone names known to CLDR.

Returns the place named by the generic location format for a timezone.

Returns the CLDR metazone for an IANA timezone name.

Returns the specific or generic non-location timezone name.

Parses a fixed UTC offset from a time zone string.

Parses a time zone written in any of the forms a locale formats one in.

Resolves a time zone written in any form parse_zone/2 reads, at a date and time, to the DateTime.t/0 it names.

Returns the BCP 47 short timezone identifier for an IANA timezone name.

Returns a mapping of IANA time zone names to their known territory.

Returns the count of timezones for a given territory.

Returns a mapping of CLDR short zone codes to IANA timezone names.

Returns a mapping of territories to their known IANA timezone names.

Returns a list of timezone maps for a given territory.

Validates a CLDR short zone code and returns the canonical IANA timezone name.

Returns the IANA timezone that represents a CLDR metazone.

Functions

exemplar_city(iana_id, locale \\ Localize.get_locale(), options \\ [])

@spec exemplar_city(String.t(), Localize.locale(), Keyword.t()) ::
  {:ok, String.t()} | {:error, Exception.t()}

Returns the exemplar city for an IANA timezone identifier.

CLDR names a representative city for most timezones — the city a reader would recognise the zone by — localized, and sometimes differing from the city in the identifier: "America/Godthab" is "Nuuk", which is what the place is now called.

Arguments

  • iana_id is an IANA timezone identifier such as "America/Los_Angeles" or "America/Indiana/Knox".

  • locale is a locale identifier or a Localize.LanguageTag.t/0. The default is Localize.get_locale/0.

  • options is a keyword list of options.

Options

  • :derive determines what happens when CLDR names no exemplar city for the zone. true, the default, derives one from the identifier, so "Pacific/Wallis" yields "Wallis". false returns an error instead, which distinguishes a name CLDR vouches for from one this library invented.

Returns

  • {:ok, city}, or

  • {:error, exception} if the locale is unknown, or if the zone has no exemplar city and derive: false was given.

Examples

iex> Localize.DateTime.Timezone.exemplar_city("America/Los_Angeles", :en)
{:ok, "Los Angeles"}

iex> Localize.DateTime.Timezone.exemplar_city("America/Godthab", :en)
{:ok, "Nuuk"}

iex> Localize.DateTime.Timezone.exemplar_city("America/Indiana/Knox", :en)
{:ok, "Knox, Indiana"}

iex> Localize.DateTime.Timezone.exemplar_city("Atlantic/Azores", :de)
{:ok, "Azoren"}

iex> {:error, exception} =
...>   Localize.DateTime.Timezone.exemplar_city("Neverwhere/Nowhere", :en, derive: false)
iex> exception.__struct__
Localize.UnknownTimezoneError

fetch_short_zone(short_zone)

@spec fetch_short_zone(String.t()) :: {:ok, map()} | {:error, Exception.t()}

Returns {:ok, map} for a given CLDR short zone code, or :error if no such short code exists.

Arguments

  • short_zone is a CLDR short timezone code string.

Returns

  • {:ok, map} where map has :aliases, :preferred, and :territory keys.

  • {:error, exception} if the short zone code is not found.

Examples

iex> Localize.DateTime.Timezone.fetch_short_zone("ausyd")
{
  :ok,
  %{
    preferred: nil,
    aliases: ["Australia/Sydney", "Australia/ACT", "Australia/Canberra", "Australia/NSW"],
    territory: :AU
  }
}

iex> match?({:error, _}, Localize.DateTime.Timezone.fetch_short_zone("nope"))
true

generic_location_format(iana_id, locale \\ Localize.get_locale())

@spec generic_location_format(String.t(), Localize.locale()) ::
  {:ok, String.t()} | :error

Returns the generic location format for a timezone.

This is the V format symbol at width four: the zone's location substituted into the locale's generic regionFormat, so Australia/Adelaide in en is "Adelaide Time".

Arguments

Returns

  • {:ok, formatted_string}.

  • :error for a zone with no place to name — the Etc/* zones, for which TR35 falls back to the localized GMT format — or when the locale has no regionFormat.

Examples

iex> Localize.DateTime.Timezone.generic_location_format("Australia/Adelaide", :en)
{:ok, "Adelaide Time"}

iex> Localize.DateTime.Timezone.generic_location_format("Europe/Rome", :en)
{:ok, "Italy Time"}

iex> Localize.DateTime.Timezone.generic_location_format("Etc/GMT", :en)
:error

get_short_zone(short_zone, default \\ nil)

@spec get_short_zone(String.t(), term()) :: map() | term()

Returns a timezone map for a given CLDR short zone code, or a default value.

Arguments

  • short_zone is a CLDR short timezone code string.

  • default is the value to return if the short zone is not found. Defaults to nil.

Returns

  • A map with :aliases, :preferred, and :territory keys, or the default value.

Examples

iex> Localize.DateTime.Timezone.get_short_zone("ausyd")
%{
  preferred: nil,
  aliases: ["Australia/Sydney", "Australia/ACT", "Australia/Canberra", "Australia/NSW"],
  territory: :AU
}

iex> Localize.DateTime.Timezone.get_short_zone("nope")
nil

gmt_format(datetime, locale_id, options \\ [])

@spec gmt_format(map(), atom(), Keyword.t()) ::
  {:ok, String.t()} | {:error, Exception.t()}

Returns the localized GMT offset format.

Uses the locale's gmt_format pattern (e.g., ["GMT", 0]) and hour_format pattern to render the datetime's total UTC offset.

Arguments

  • datetime is a map with an integer :utc_offset in seconds and optionally an integer :std_offset in seconds (a DateTime.t/0 satisfies this shape).

  • locale_id is a resolved locale identifier atom (e.g., :en), such as the cldr_locale_id of a validated Localize.LanguageTag.t/0. It is passed directly to Localize.Locale.get/2 and is not validated or canonicalized by this function.

  • options is a keyword list of options.

Options

  • :format is :long (e.g., "GMT+01:00") or :short (e.g., "GMT+1"; minutes are dropped when zero). The default is :long. TR35 gives the long format a two-digit hour and the short format an hour with no leading zero, whichever the locale's hourFormat writes: "UTC+05.30" and "UTC+5.30" in fi, whose pattern is "+H.mm". Both write the seconds of an offset that has them, as the offsets zones kept before standard time do: "GMT-07:52:58" and "GMT-7:52:58".

  • :number_system is the numbering system whose digits write the offset, as TR35 has it written in the locale's digits ("GMT-४" in ne). The default is the locale's default numbering system. A system without digits of its own writes 0 to 9.

  • :designation is :gmt, the locale's gmtFormat, or :utc, CLDR 49's alt="utc" form. The default is :gmt. "GMT" names a zone connected with London as well as Coordinated Universal Time, so :utc asks for the locale's unambiguous designation for the latter: "UTC+01:00" in en, "التوقيت العالمي+١:٠٠" in ar against its "غرينتش+١:٠٠". Many locales spell the two alike. Both spellings read back through parse_offset/2.

  • :offsets is :single, the offset the value carries, or :dual, the pair the zone keeps joined by CLDR 49's dualOffsetFormat. The default is :single. A zone that moves between standard and daylight time is poorly described by whichever offset it happens to keep at one time, so :dual writes both — Los Angeles is "GMT-8/-7" where Phoenix, which keeps one offset, stays "GMT-7". The pair comes from the time zone database the application configures, read across the year around the value's time, so a value with no :time_zone, or a zone the database cannot place, writes the single offset. The result names a zone rather than a time and does not read back through parse_offset/2.

Returns

  • {:ok, formatted_string} (e.g., "GMT+01:00"). A zero offset is spelled out — "GMT+00:00" long, "GMT+0" short — which is the only style TR35 defines for a known offset.

  • {:ok, unknown} using the locale's gmtUnknownFormat (e.g. "GMT+?"), or its alt="utc" form for designation: :utc, when datetime carries no offset at all. TR35 makes this the second of the two localized GMT styles.

  • {:error, exception} if the locale's timezone data cannot be loaded, or if :designation or :offsets is not one of the values above.

Examples

iex> Localize.DateTime.Timezone.gmt_format(%{utc_offset: 3600, std_offset: 0}, :en)
{:ok, "GMT+01:00"}

iex> Localize.DateTime.Timezone.gmt_format(%{utc_offset: -28800, std_offset: 0}, :en, format: :short)
{:ok, "GMT-8"}

iex> Localize.DateTime.Timezone.gmt_format(%{utc_offset: -14400, std_offset: 0}, :ne, format: :short)
{:ok, "GMT-४"}

iex> Localize.DateTime.Timezone.gmt_format(%{utc_offset: 3600, std_offset: 0}, :en, designation: :utc)
{:ok, "UTC+01:00"}

iex> datetime = DateTime.new!(~D[2026-01-15], ~T[12:00:00], "America/Los_Angeles")
iex> Localize.DateTime.Timezone.gmt_format(datetime, :en, format: :short, offsets: :dual)
{:ok, "GMT-8/-7"}

iex> datetime = DateTime.new!(~D[2026-01-15], ~T[12:00:00], "America/Phoenix")
iex> Localize.DateTime.Timezone.gmt_format(datetime, :en, format: :short, offsets: :dual)
{:ok, "GMT-7"}

iso_format(datetime, options \\ [])

@spec iso_format(map(), Keyword.t()) :: {:ok, String.t()} | {:error, Exception.t()}

Returns the ISO 8601 timezone offset format.

This function is locale-independent — ISO 8601 offsets are the same in every locale.

Arguments

  • datetime is a map with an integer :utc_offset in seconds and optionally an integer :std_offset in seconds (a DateTime.t/0 satisfies this shape).

  • options is a keyword list of options.

Options

  • :format is :short (minutes omitted when zero), :long (hours and minutes), or :full (like :long, with seconds appended when non-zero). The default is :long.

  • :type is :basic (no separator, e.g., "+0500") or :extended (colon separator, e.g., "+05:00"). The default is :basic.

  • :z_for_zero is a boolean controlling whether a zero offset renders as "Z". The default is true.

Returns

  • {:ok, formatted_string} (e.g., "+0500", "Z", "+05:00").

Examples

iex> Localize.DateTime.Timezone.iso_format(%{utc_offset: 18000, std_offset: 0})
{:ok, "+0500"}

iex> Localize.DateTime.Timezone.iso_format(%{utc_offset: 19800, std_offset: 0}, type: :extended)
{:ok, "+05:30"}

iex> Localize.DateTime.Timezone.iso_format(%{utc_offset: 0, std_offset: 0})
{:ok, "Z"}

known_timezones()

@spec known_timezones() :: [String.t(), ...]

Returns the canonical IANA time zone names known to CLDR.

The canonical name is the first alias of each BCP 47 short zone in the CLDR timezone data; short zones with no IANA mapping are omitted. This is the inventory backing ECMA-402's Intl.supportedValuesOf("timeZone").

Returns

  • A sorted list of IANA time zone name strings.

Examples

iex> zones = Localize.DateTime.Timezone.known_timezones()
iex> "Australia/Sydney" in zones and "America/New_York" in zones
true

iex> Localize.DateTime.Timezone.known_timezones() |> hd()
"Africa/Abidjan"

location_name(iana_id, locale \\ Localize.get_locale(), options \\ [])

@spec location_name(String.t(), Localize.locale(), Keyword.t()) ::
  {:ok, String.t()} | {:error, Exception.t()}

Returns the place named by the generic location format for a timezone.

TR35 names a country when the zone is the only one in its territory, or when CLDR lists it as that territory's primary zone, and names the zone's exemplar city otherwise. So Europe/Rome is "Italy" — Italy keeps one zone — while Australia/Adelaide is "Adelaide".

Arguments

Options

  • :derive is a boolean determining whether an exemplar city may be derived from the timezone identifier when CLDR names none. The default is true.

Returns

  • {:ok, place_name} where the place is a country or a city. A country the locale has no name for is its code, as TR35 composes a location.

  • {:error, exception} if the locale is unknown, or if no city can be found or derived for the timezone.

Examples

iex> Localize.DateTime.Timezone.location_name("Europe/Rome", :en)
{:ok, "Italy"}

iex> Localize.DateTime.Timezone.location_name("Europe/Berlin", :en)
{:ok, "Germany"}

iex> Localize.DateTime.Timezone.location_name("Australia/Adelaide", :en)
{:ok, "Adelaide"}

iex> Localize.DateTime.Timezone.location_name("America/Havana", :su)
{:ok, "CU"}

metazone_for(time_zone, datetime \\ nil)

@spec metazone_for(String.t(), map() | nil) :: atom() | nil

Returns the CLDR metazone for an IANA timezone name.

Zones move between metazones over time (for example America/Indiana/Knox has alternated between the central and eastern metazones), so the datetime selects the applicable usage period.

A zone keeps no metazone before 1970. CLDR tells zones apart back to 1970, and where it gives a zone's first period no beginning the period begins at 00:00 on 1 January 1970 in UTC. Before that a zone is written by its own names, its offset and its location: New York in 1965 is "GMT-05:00" and "New York Time".

Arguments

  • time_zone is an IANA timezone name (e.g., "America/New_York") or any of its CLDR aliases (e.g., "Asia/Calcutta").

  • datetime is a map that may carry :year .. :second fields selecting the metazone in effect at that instant. The fields are read in the map's :calendar, Calendar.ISO when it has none. When the fields are absent (or datetime is nil), or name no day of the calendar, the currently effective metazone is returned. The default is nil.

Returns

  • The metazone as an atom (e.g., :america_eastern), matching the keys of the locale time_zone_names.metazone data.

  • nil when the zone has no metazone mapping for the instant.

Examples

iex> Localize.DateTime.Timezone.metazone_for("America/New_York")
:america_eastern

iex> Localize.DateTime.Timezone.metazone_for("Asia/Calcutta")
:india

iex> Localize.DateTime.Timezone.metazone_for("America/Indiana/Knox", ~N[2000-06-01 00:00:00])
:america_eastern

iex> Localize.DateTime.Timezone.metazone_for("America/Indiana/Knox", ~N[2020-06-01 00:00:00])
:america_central

iex> Localize.DateTime.Timezone.metazone_for("America/New_York", ~N[1969-12-31 23:59:59])
nil

non_location_format(datetime, locale_id, options \\ [])

@spec non_location_format(map(), Localize.locale(), Keyword.t()) ::
  {:ok, String.t()} | {:error, Exception.t()}

Returns the specific or generic non-location timezone name.

Looks up the zone's own name, then its metazone name, in the locale's timezone data (e.g., "Eastern Standard Time"). When the locale carries neither, falls back to gmt_format/3.

A metazone's name is shared by every zone that keeps it, so it is qualified as TR35 gives for the non-location formats, generic and specific alike: written as it is for the metazone's preferred zone for the locale's country, with the zone's country where it is that country's preferred zone ("Pacific Standard Time (Canada)" for Vancouver in en), and with its city otherwise ("Mountain Standard Time (Phoenix)"). A zone's own name is not qualified.

Arguments

  • datetime is a map with :time_zone, :utc_offset, and :std_offset keys (a DateTime.t/0 satisfies this shape).

  • locale_id is a resolved locale identifier atom (e.g., :en), such as the cldr_locale_id of a validated Localize.LanguageTag.t/0. It is passed directly to Localize.Locale.get/2 and is not validated or canonicalized by this function.

  • options is a keyword list of options.

Options

  • :format is :short (e.g., "EST") or :long (e.g., "Eastern Standard Time"). The default is :long.

  • :type is :specific (standard or daylight name chosen from the datetime's :std_offset), :generic, :standard, or :daylight. The default is :specific.

  • :number_system is the numbering system whose digits write the offset where the name falls back to gmt_format/3. The default is the locale's default numbering system.

  • :designation is :gmt or :utc, choosing the designation the fallback to gmt_format/3 spells its offset with. The default is :gmt. It has no effect where the locale names the zone.

Returns

  • {:ok, timezone_name} with the localized non-location name, or {:ok, gmt_offset_string} when falling back to the GMT format.

  • {:error, exception} if the locale's timezone data cannot be loaded, or :type or :designation is not one of the values above.

Examples

iex> datetime = %{time_zone: "America/New_York", utc_offset: -18000, std_offset: 0}
iex> Localize.DateTime.Timezone.non_location_format(datetime, :en, format: :long)
{:ok, "Eastern Standard Time"}

iex> datetime = %{time_zone: "America/New_York", utc_offset: -18000, std_offset: 0}
iex> Localize.DateTime.Timezone.non_location_format(datetime, :en, format: :short)
{:ok, "EST"}

iex> datetime = %{time_zone: "America/Vancouver", utc_offset: -28800, std_offset: 0}
iex> Localize.DateTime.Timezone.non_location_format(datetime, :en)
{:ok, "Pacific Standard Time (Canada)"}

parse_offset(zone_string, options \\ [])

@spec parse_offset(String.t(), Keyword.t()) ::
  {:ok, integer()} | {:error, Exception.t()}

Parses a fixed UTC offset from a time zone string.

This is the inverse of gmt_format/3 and iso_format/2. It resolves only offsets that are pure arithmetic — an ISO 8601 offset, or the localized GMT format in the locale's own spelling. A named zone ("PST", "Asia/Tokyo") carries no offset of its own and needs a time-zone database to resolve; it is rejected here.

The offset is read in the digits of any numbering system, whatever the locale, as TR35's parsing reads the localized GMT format with "non-Latin numbers": gmt_format/3 writes it in the locale's digits.

TR35 has that format's number read leniently: as "03, 3, 330, 3:30, 33045 or 3:30:45", with spaces around its sign, and with "+, -, or nothing" before it, so a number with no sign after the GMT literal is an offset east of it. A number before a literal that follows it needs its sign, being as much a time of day in that zone ("10:30 GMT").

Arguments

  • zone_string is the zone portion of a parsed time, such as "Z", "+05:30", "GMT+10:30" or a locale's own GMT spelling.

  • options is a keyword list of options.

Options

  • :locale is a locale identifier, used to recognise that locale's GMT format. The default is the locale returned by Localize.get_locale/0.

Returns

  • {:ok, offset} where offset is the number of seconds east of UTC, negative for offsets west of it.

  • {:error, exception}, a Localize.UnknownTimezoneError.t/0, when the string carries no fixed offset.

Examples

iex> Localize.DateTime.Timezone.parse_offset("+05:30")
{:ok, 19800}

iex> Localize.DateTime.Timezone.parse_offset("Z")
{:ok, 0}

iex> Localize.DateTime.Timezone.parse_offset("GMT-8")
{:ok, -28800}

iex> Localize.DateTime.Timezone.parse_offset("GMT+५:३०", locale: :ne)
{:ok, 19800}

iex> Localize.DateTime.Timezone.parse_offset("GMT 3")
{:ok, 10800}

iex> Localize.DateTime.Timezone.parse_offset("Asia/Tokyo")
{:error, %Localize.UnknownTimezoneError{timezone: "Asia/Tokyo"}}

parse_zone(zone_string, options \\ [])

@spec parse_zone(String.t(), Keyword.t()) ::
  {:ok,
   {:offset, integer()} | {:zone, String.t(), :generic | :standard | :daylight}}
  | {:error, Exception.t()}

Parses a time zone written in any of the forms a locale formats one in.

TR35's time zone parsing reads a zone as an ISO 8601 offset, the localized GMT format in the locale's spelling or the global one, in the digits of any numbering system ("GMT-4", "UTC−4", "غرينتش-4", "غرينتش-٤"), a zone ID ("America/New_York") or its short form ("usnyc"), an exemplar city ("New York"), a location ("New York Time", "heure : New York"), or a zone or metazone name, long or short, generic, standard or daylight ("Eastern Time", "EDT", "heure d’été de l’Est nord-américain"), alone or with a city or country in the locale's fallback format ("Pacific Time (Canada)").

A country with one zone stands for that zone, and a city or a zone's own name is read before a metazone's, as TR35 orders them: "Chile Time (Punta Arenas)" is America/Punta_Arenas. A metazone name stands for the metazone's zone in the country the string names, else in the locale's country, else its golden zone, so "Mitteleuropäische Zeit" is Europe/Berlin in de and Europe/Vienna in de-AT, the zone the formatter writes that name for in each. Where several metazones share a name ("Greenwich Mean Time") the one with a zone in that country is read, else the one with zones in the most countries. A country with several zones stands for its primary zone, as its location is written ("Germany Time"), where the string names no other zone.

A country or a city in parentheses qualifies a name the locale writes, as every qualified name the formatter writes is one: "xyz (Italy)" is no zone, though TR35's sample process reads it as Italy's whatever stands before the country.

Arguments

  • zone_string is the zone as written.

  • options is a keyword list of options.

Options

Returns

  • {:ok, {:offset, offset}} for a fixed offset, in seconds east of UTC.

  • {:ok, {:zone, time_zone, type}} for a time zone, by CLDR's canonical IANA name, where type is :standard or :daylight for a name of that time and :generic for every other form.

  • {:error, exception} when the string is not a zone the locale writes.

Examples

iex> Localize.DateTime.Timezone.parse_zone("Eastern Daylight Time", locale: :en)
{:ok, {:zone, "America/New_York", :daylight}}

iex> Localize.DateTime.Timezone.parse_zone("heure : New York", locale: :fr)
{:ok, {:zone, "America/New_York", :generic}}

iex> Localize.DateTime.Timezone.parse_zone("Pacific Time (Canada)", locale: :en)
{:ok, {:zone, "America/Vancouver", :generic}}

iex> Localize.DateTime.Timezone.parse_zone("GMT-4", locale: :en)
{:ok, {:offset, -14400}}

resolve(zone_string, naive_datetime, options \\ [])

@spec resolve(String.t(), NaiveDateTime.t(), Keyword.t()) ::
  {:ok, DateTime.t()} | {:error, Exception.t()}

Resolves a time zone written in any form parse_zone/2 reads, at a date and time, to the DateTime.t/0 it names.

A fixed offset resolves on its own, as a DateTime.t/0 at that offset, whose time zone is the offset itself, "+05:30", and "Etc/UTC" for no offset at all. A time zone's offset depends on the date, so it needs the time zone database the application configures, such as :tz (config :elixir, :time_zone_database, Tz.TimeZoneDatabase).

A name of standard or daylight time is the zone's own DateTime.t/0 on a date the zone keeps that time, as the formatter names it: by the offsets CLDR names standard and daylight for the zone's metazone where it gives them (Punta Arenas keeps Chile's summer time all year), and else as the time zone database says. On any other date the name keeps its own offset, which TR35 allows such a name to read back as ("or to just an offset"): "10:00 EST" in July is 10:00 at -05:00, a fixed offset, since New York keeps daylight time then. A standard name whose zone and metazone have no daylight name in the locale stands for every type, as TR35's type fallback has it, and follows the zone's clock.

Any other form follows the zone's clock, and a wall time its clocks pass twice is read in standard time, TR35's example for a generic format "when the local time maps to two possible GMT times" being one "favoring standard time". A time they skip is read at the offset before the change; of that TR35 says only that "there can also be a gap".

Some strings have more than one reading: it's "Ora dell’Europa orientale (Kaliningrad)" names a metazone no zone has kept since 2014 and is also Eastern European time in Kaliningrad, and "Malaysia Time" is the time of Kuching and the location of Kuala Lumpur, which kept another time until 1982. The date decides between them: the reading taken is the first whose zone is written as that string on the date, where parse_zone/2, which has no date, gives the first of them.

Arguments

  • zone_string is the zone as written.

  • naive_datetime is the date and time written with it, a NaiveDateTime.t/0 in any calendar.

  • options is a keyword list of options.

Options

Returns

  • {:ok, datetime}.

  • {:error, exception} when the string is not a zone the locale writes, or names a time zone the configured database does not resolve, as Elixir's default database resolves none but UTC.

Examples

iex> {:ok, datetime} =
...>   Localize.DateTime.Timezone.resolve("UTC−4", ~N[2023-07-15 10:05:00], locale: :fr)
iex> {datetime.utc_offset, DateTime.to_naive(datetime)}
{-14400, ~N[2023-07-15 10:05:00]}

short_zone_id(iana_id)

@spec short_zone_id(String.t()) :: String.t()

Returns the BCP 47 short timezone identifier for an IANA timezone name.

This is the value of the V format symbol in TR35. Every alias of a zone resolves to the same short identifier, so both "America/New_York" and its alias "US/Eastern" return "usnyc".

Arguments

  • iana_id is an IANA timezone name such as "America/New_York".

Returns

  • The BCP 47 short timezone identifier as a string.

  • "unk", the Unknown Zone identifier, if iana_id is not a known timezone. TR35 specifies this as the fallback for the V symbol.

Examples

iex> Localize.DateTime.Timezone.short_zone_id("America/New_York")
"usnyc"

iex> Localize.DateTime.Timezone.short_zone_id("US/Eastern")
"usnyc"

iex> Localize.DateTime.Timezone.short_zone_id("Not/AZone")
"unk"

territories_by_timezone()

@spec territories_by_timezone() :: %{required(String.t()) => atom()}

Returns a mapping of IANA time zone names to their known territory.

A time zone can only belong to one territory in CLDR.

Returns

  • A map where each key is an IANA timezone string and each value is a territory atom.

Examples

iex> territories = Localize.DateTime.Timezone.territories_by_timezone()
iex> Map.get(territories, "Australia/Sydney")
:AU

timezone_count_for_territory(territory)

@spec timezone_count_for_territory(atom()) ::
  {:ok, non_neg_integer()} | {:error, Exception.t()}

Returns the count of timezones for a given territory.

Arguments

  • territory is a territory atom like :US or :AU.

Returns

  • {:ok, count} where count is the number of timezones.

  • {:error, exception} if the territory has no known timezones.

Examples

iex> {:ok, count} = Localize.DateTime.Timezone.timezone_count_for_territory(:AU)
iex> count > 0
true

timezones()

@spec timezones() :: %{required(String.t()) => map()}

Returns a mapping of CLDR short zone codes to IANA timezone names.

Each key is a BCP 47 short timezone identifier string and each value is a map with :aliases, :preferred, and :territory keys.

Returns

  • A map of %{String.t() => map()}.

Examples

iex> timezones = Localize.DateTime.Timezone.timezones()
iex> Map.get(timezones, "ausyd")
%{preferred: nil, aliases: ["Australia/Sydney", "Australia/ACT", "Australia/Canberra", "Australia/NSW"], territory: :AU}

timezones_by_territory()

@spec timezones_by_territory() :: %{
  required(atom()) => [
    %{
      short_zone: String.t(),
      territory: atom(),
      aliases: [term(), ...],
      preferred: nil | String.t()
    },
    ...
  ]
}

Returns a mapping of territories to their known IANA timezone names.

Returns

  • A map where each key is a territory atom and each value is a list of timezone maps including :short_zone, :aliases, :preferred, and :territory keys.

Examples

iex> {:ok, zones} = Localize.DateTime.Timezone.timezones_for_territory(:AU)
iex> Enum.any?(zones, & &1.short_zone == "ausyd")
true

timezones_for_territory(territory)

@spec timezones_for_territory(atom()) :: {:ok, [map()]} | {:error, Exception.t()}

Returns a list of timezone maps for a given territory.

Arguments

  • territory is a territory atom like :US or :AU.

Returns

  • {:ok, list} where list is timezone maps for the territory.

  • {:error, exception} if the territory has no known timezones.

Examples

iex> {:ok, zones} = Localize.DateTime.Timezone.timezones_for_territory(:US)
iex> is_list(zones)
true

validate_short_zone(short_zone)

@spec validate_short_zone(String.t()) :: {:ok, String.t()} | {:error, Exception.t()}

Validates a CLDR short zone code and returns the canonical IANA timezone name.

Arguments

  • short_zone is a CLDR short timezone code string.

Returns

  • {:ok, iana_name} where iana_name is the canonical IANA timezone name string.

  • {:error, exception} if the short zone code is not valid.

Examples

iex> Localize.DateTime.Timezone.validate_short_zone("ausyd")
{:ok, "Australia/Sydney"}

iex> Localize.DateTime.Timezone.validate_short_zone("nope")
{:error, %Localize.UnknownTimezoneError{timezone: "nope"}}

zone_for_metazone(metazone, territory \\ :"001")

@spec zone_for_metazone(atom(), atom()) :: String.t() | nil

Returns the IANA timezone that represents a CLDR metazone.

Arguments

  • metazone is a metazone atom as returned by metazone_for/2 (e.g., :america_pacific).

  • territory is a territory atom used to select a territory-specific representative zone (e.g., :CA selects "America/Vancouver" for :america_pacific). The default is :"001", the metazone's golden zone.

Returns

  • The IANA timezone name for the territory, falling back to the metazone's golden zone when the territory has no specific mapping.

  • nil when the metazone is unknown.

Examples

iex> Localize.DateTime.Timezone.zone_for_metazone(:america_pacific)
"America/Los_Angeles"

iex> Localize.DateTime.Timezone.zone_for_metazone(:america_pacific, :CA)
"America/Vancouver"

iex> Localize.DateTime.Timezone.zone_for_metazone(:no_such_metazone)
nil