# `TzWorld`
[🔗](https://github.com/kipcole9/tz_world/blob/v2.3.0/lib/tz_world.ex#L1)

Resolve a timezone name from coordinates.

# `backend`

```elixir
@type backend() :: module()
```

# `backend_result`

```elixir
@type backend_result() :: {:ok, term()} | {:error, term()}
```

# `all_timezones_at`

```elixir
@spec all_timezones_at(Geo.Point.t(), backend()) :: {:ok, [String.t()]}
@spec all_timezones_at(Geo.PointZ.t(), backend()) :: {:ok, [String.t()]}
@spec all_timezones_at(
  {lng :: number(), lat :: number()},
  backend()
) :: {:ok, [String.t()]}
```

Returns all timezone name found for the given
coordinates specified as either a `Geo.Point`,
a `Geo.PointZ` or a tuple `{lng, lat}`

## Arguments

* `point` is a `Geo.Point.t()` a `Geo.PointZ.t()` or
  a tuple `{lng, lat}`

* `backend` is any backend access module.

## Returns

* `{:ok, timezone}` or

* `{:error, :time_zone_not_found}`

## Notes

Note that the point is always expressed as
`lng` followed by `lat`.

## Examples

    iex> TzWorld.all_timezones_at(%Geo.Point{coordinates: {3.2, 45.32}})
    {:ok, ["Europe/Paris"]}

    iex> TzWorld.all_timezones_at({3.2, 45.32})
    {:ok, ["Europe/Paris"]}

    iex> TzWorld.all_timezones_at({0.0, 0.0})
    {:ok, []}

The algorithm starts by filtering out timezones whose bounding
box does not contain the given point.

Once filtered, all timezones which contains the given
point is returned, or an error tuple if none of the
timezones match.

In rare cases, typically due to territorial disputes,
one or more timezones may apply to a given location.
This function returns all time zones that match.

# `app_name`

Returns the OTP app name of :tz_world

# `fetch_backend`

# `reload_timezone_data`

```elixir
@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. `results` is a list of `{backend, result}` pairs
  in reload order.

* `{:error, failures}` when one or more running backends failed
  to reload. `failures` is 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`)
  because `EtsWithIndexCache` reads from the DETS file rebuilt
  by `DetsWithIndexCache`.

* 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: `SpatialIndex` swaps 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. `:stop` measurements include `:duration`. `:stop`
  metadata 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). `:stop` metadata also includes `:result`.

### Example

    # An app running only the default backend
    TzWorld.reload_timezone_data()
    #=> {:ok, [{TzWorld.Backend.SpatialIndex, {:ok, :loaded}}]}

# `timezone_at`

```elixir
@spec timezone_at(Geo.Point.t(), backend()) :: {:ok, String.t()} | {:error, atom()}
@spec timezone_at(Geo.PointZ.t(), backend()) :: {:ok, String.t()} | {:error, atom()}
@spec timezone_at(
  {lng :: number(), lat :: number()},
  backend()
) :: {:ok, String.t()} | {:error, atom()}
```

Returns the *first* timezone name found for the given
coordinates specified as either a `Geo.Point`,
a `Geo.PointZ` or a tuple `{lng, lat}`

## Arguments

* `point` is a `Geo.Point.t()` a `Geo.PointZ.t()` or
  a tuple `{lng, lat}`

* `backend` is any backend access module.

## Returns

* `{:ok, timezone}` or

* `{:error, :time_zone_not_found}`

## Notes

Note that the point is always expressed as
`lng` followed by `lat`.

## 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}

The algorithm starts by filtering out timezones whose bounding
box does not contain the given point.

Once filtered, the *first* timezone which contains the given
point is returned, or an error tuple if none of the
timezones match.

In rare cases, typically due to territorial disputes,
one or more timezones may apply to a given location.
This function returns the first time zone that matches.

# `version`

```elixir
@spec version() :: {:ok, String.t()} | {:error, :enoent}
```

Returns the installed version of time
zone data

## Example

    TzWorld.version
    => {:ok, "2020d"}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
