TzWorld

hex.pmhex.pmhex.pmgithub.com

Resolve timezones from a location using data from the timezone-boundary-builder project.

Installation

Add tz_world to your list of dependencies in mix.exs:

def deps do
  [
    {:tz_world, "~> 1.3"}
  ]
end

After adding TzWorld as a dependency, run mix deps.get to install it. Then run mix tz_world.update to install the timezone data.

NOTE No data is installed with the package and until the data is installed with mix tz_world.update all calls to TzWorld.timezone_at/1 will return {:error, :time_zone_not_found}.

Configuration

There is no mandatory configuration required however four options may be configured in config.exs:

config :tz_world,
  # Configure a custom TzWorld backend. It will be used
  # as the default backend in calls to `TzWorld.timezone_at/1`
  backend: MyTzWorldBackend,
  # The default is the `priv` directory of `:tz_world`
  data_dir: "geodata/directory",
  # The default is either the trust store included in the
  # libraries `CAStore` or `certifi` or the platform
  # trust store.
  cacertfile: "path/to/ca_trust_store",
  # The default is no options, however one can set any `httpc` client options.
  httpc_opts: [
    proxy: {{String.to_charlist(proxy_host), proxy_port}, []}
  ]

Backend selection

TzWorld provides alternative strategies for managing access to the backend data. Each backend is implemented as a GenServer that needs to be either manually started with BackendModule.start_link/1 or preferably added to your application's supervision tree.

The recommended backend is TzWorld.Backend.EtsWithIndexCache unless the host system is memory constrained in which case TzWorld.Backend.DetsWithIndexCache is recommended.

For example:

defmodule MyApp.Application do
  @moduledoc false

  use Application

  def start(_type, _args) do
    children = [
      ...
      TzWorld.Backend.EtsWithIndexCache
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

The following backends are available:

Other backends can be implemented as long as they follow the TzWorld.Backend behaviour. Custom backends should be configured in config.exs or runtime.exs under the :backend key so that it will be considered as the default for calls to TzWorld.timezone_at/1. For example:

config :tz_world,
  backend: MyTzWorldBackend

Installing the Timezones Geo JSON data

Installing tz_world from source or from hex does not include the timezones Geo JSON data. The data is required and to install or update it run:

mix tz_worldÆ’

This task will download, transform, zip and store the timezones Geo data. Depending on internet and computer speed this may take a few minutes.

By default mix tz_world.update will download geojson data that does not include time zone information for the oceans. There are two optional parameters that are accepted by mix tz_world.update that can be used to configure the desired behaviour:

Updating the Timezone data

From time-to-time the timezones Geo JSON data is updated in the upstream project. The mix task mix tz_world.update will update the data if it is available.

A running application can also be instructed to reload the data by executing TzWorld.reload_timezone_data.

Usage

The primary API is TzWorld.timezone_at. It takes either a Geo.Point struct or a longitude and latitude in degrees. Note the parameter order: longitude, latitude. It also takes and optional second parameter, backend, which must be one of the configured and running backend modules. By default timezone_at/2 will detect a running backend and will raise an exception if no running backend is found.

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(%Geo.PointZ{coordinates: {-74.006, 40.7128, 0.0}})
{:ok, "America/New_York"}

# Assumes that the downloaded data does not include
# data for the oceans (the default)
iex> TzWorld.timezone_at(%Geo.Point{coordinates: {1.3, 65.62}})
{:error, :time_zone_not_found}