Resolves the time zone at a location from its coordinates.
Time zone boundaries come from the
timezone-boundary-builder
project. They are not included in the package: mix tz_world.update
downloads and installs them, and lookups return {:error, :enoent}
until it has run.
Lookups are answered by a backend running in the application's
supervision tree, normally TzWorld.Backend.SpatialIndex.
Public API
timezone_at/2returns the time zone at a point.all_timezones_at/2returns every time zone at a point, for the few places where zones overlap.version/0returns the version of the installed data.reload_timezone_data/0reloads the running backends after the data is updated.
Summary
Types
A backend module implementing TzWorld.Backend.
A location as a Geo.Point, a Geo.PointZ or a {longitude, latitude}
tuple, in degrees.
Functions
Returns every time zone at a point.
Returns the OTP application name of tz_world.
Reload the timezone geometry data from the on-disk files.
Returns the time zone at a point.
Returns the version of the installed time zone data.
Types
@type backend() :: module()
A backend module implementing TzWorld.Backend.
@type point() :: Geo.Point.t() | Geo.PointZ.t() | {lng :: number(), lat :: number()}
A location as a Geo.Point, a Geo.PointZ or a {longitude, latitude}
tuple, in degrees.
Functions
Returns every time zone at a point.
Most points are in exactly one time zone. A few, in disputed territories, are in more than one, and points outside every time zone are in none.
Arguments
pointis aGeo.Point, aGeo.PointZor a{longitude, latitude}tuple, in degrees. Longitude always comes first.backendis the backend module to query. The default is the running backend, preferring the configured:default_backend. ARuntimeErroris raised if no backend is running.
Returns
{:ok, time_zones}wheretime_zonesis a list of time zone names in the order they were found, empty if no time zone contains the point.{:error, :invalid_point}ifpointis not one of the forms above, or its longitude is outside -180..180 or its latitude outside -90..90.{:error, :enoent}if the time zone data has not been installed. Runmix tz_world.updateto install it.
Examples
iex> TzWorld.all_timezones_at({3.2, 45.32})
{:ok, ["Europe/Paris"]}
iex> TzWorld.all_timezones_at({87.6168, 43.8256})
{:ok, ["Asia/Shanghai", "Asia/Urumqi"]}
iex> TzWorld.all_timezones_at({0.0, 0.0})
{:ok, []}
@spec app_name() :: :tz_world
Returns the OTP application name of tz_world.
Returns
:tz_world.
Examples
iex> TzWorld.app_name()
:tz_world
@spec reload_timezone_data() :: {:ok, [{module(), backend_result()}]} | {:error, [{module(), term()}]}
Reload the timezone geometry data from the on-disk files.
Iterates the list of known backends and asks each one that is currently running in this node to reload itself from disk. Backends that are not running are skipped — the function is safe to call regardless of which backends the host application has added to its supervision tree.
Returns
{:ok, results}when every running backend reloaded successfully.resultsis a list of{backend, result}pairs in reload order.{:error, failures}when one or more running backends failed to reload.failuresis a list of{backend, reason}pairs for the backends that did not return{:ok, _}.
Notes
Reload is performed sequentially in a fixed order (
DetsWithIndexCache,EtsWithIndexCache,SpatialIndex) becauseEtsWithIndexCachereads from the DETS file rebuilt byDetsWithIndexCache.Each backend's reload runs inside its own GenServer call, so concurrent reload requests against a single backend are serialized at its mailbox.
Lookups during reload are safe:
SpatialIndexswaps its persistent-term entry atomically, and the other backends process lookup messages only after the reload returns.
Telemetry
The reload emits the following events:
[:tz_world, :reload, :start | :stop | :exception]— wraps the full call.:stopmeasurements include:duration.:stopmetadata includes:result(the return value),:backends(list of running backends that participated), and:failure_count.[:tz_world, :reload, :backend, :start | :stop | :exception]— wraps each per-backend reload. Metadata includes:backend(the module).:stopmetadata also includes:result.
Examples
In an application running only the default backend:
iex> TzWorld.reload_timezone_data()
{:ok, [{TzWorld.Backend.SpatialIndex, {:ok, :loaded}}]}
Returns the time zone at a point.
Where time zones overlap, which happens in a few disputed territories,
the first one found is returned. all_timezones_at/2 returns them all.
Arguments
pointis aGeo.Point, aGeo.PointZor a{longitude, latitude}tuple, in degrees. Longitude always comes first.backendis the backend module to query. The default is the running backend, preferring the configured:default_backend. ARuntimeErroris raised if no backend is running.
Returns
{:ok, time_zone}wheretime_zoneis the name of the time zone.{:error, :time_zone_not_found}if no time zone contains the point.{:error, :invalid_point}ifpointis not one of the forms above, or its longitude is outside -180..180 or its latitude outside -90..90.{:error, :enoent}if the time zone data has not been installed. Runmix tz_world.updateto install it.
Examples
iex> TzWorld.timezone_at(%Geo.Point{coordinates: {3.2, 45.32}})
{:ok, "Europe/Paris"}
iex> TzWorld.timezone_at({3.2, 45.32})
{:ok, "Europe/Paris"}
iex> TzWorld.timezone_at({0.0, 0.0})
{:error, :time_zone_not_found}
iex> TzWorld.timezone_at({200.0, 45.32})
{:error, :invalid_point}
@spec version() :: {:ok, String.t()} | {:error, :enoent}
Returns the version of the installed time zone data.
The version is read from the running backend.
Returns
{:ok, version}whereversionis the name of the upstream data release, such as"2026d".{:error, :enoent}if the time zone data has not been installed.
Examples
iex> {:ok, version} = TzWorld.version()
iex> is_binary(version)
true