diff --git a/CHANGELOG.md b/CHANGELOG.md index 85de142..737044d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [0.4.0](https://github.com/hopsor/open_hours/compare/v0.2.0...v0.4.0) (TBD) + +* Potentialy breaking chaneg: Make the timezone database configurable ([#41](https://github.com/hopsor/open_hours/pull/41)) + ## [0.3.0](https://github.com/hopsor/open_hours/compare/v0.2.0...v0.3.0) (2026-03-27) diff --git a/README.md b/README.md index d7e4d36..d9f7944 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,14 @@ The package can be installed by adding `open_hours` to your list of dependencies ```elixir def deps do [ - {:open_hours, "~> 0.2.0"} + {:open_hours, "~> 0.4.0"} ] end ``` +If you do not already have a timezone database (eg tz or tzdata) configured for your Elixir application +you will also need to do that. We recommend [TZ](https://tz.hexdocs.pm/readme.html) + ## Usage In order to use OpenHours functions you first need a `Schedule` config: diff --git a/lib/open_hours/offset.ex b/lib/open_hours/offset.ex index 3736ef8..9f1892f 100644 --- a/lib/open_hours/offset.ex +++ b/lib/open_hours/offset.ex @@ -98,7 +98,7 @@ defmodule OpenHours.Offset do duration ) when schedule_tz != dt_tz do - {:ok, shifted} = DateTime.shift_zone(dt, schedule_tz, Tzdata.TimeZoneDatabase) + {:ok, shifted} = DateTime.shift_zone(dt, schedule_tz, OpenHours.TimeZoneDatabase.database()) shift(schedule, shifted, duration) end @@ -142,7 +142,7 @@ defmodule OpenHours.Offset do available = DateTime.diff(slot.ends_at, position) if available >= remaining_seconds do - DateTime.add(position, remaining_seconds, :second, Tzdata.TimeZoneDatabase) + DateTime.add(position, remaining_seconds, :second, OpenHours.TimeZoneDatabase.database()) else shift_forward(schedule, slot.ends_at, remaining_seconds - available) end @@ -160,7 +160,7 @@ defmodule OpenHours.Offset do available = DateTime.diff(position, slot.starts_at) if available >= remaining_seconds do - DateTime.add(position, -remaining_seconds, :second, Tzdata.TimeZoneDatabase) + DateTime.add(position, -remaining_seconds, :second, OpenHours.TimeZoneDatabase.database()) else shift_backward(schedule, slot.starts_at, remaining_seconds - available) end @@ -206,7 +206,7 @@ defmodule OpenHours.Offset do end defp snap_to_business_time(schedule, date, time, direction) do - dt = DateTime.new!(date, time, schedule.time_zone, Tzdata.TimeZoneDatabase) + dt = DateTime.new!(date, time, schedule.time_zone, OpenHours.TimeZoneDatabase.database()) if Schedule.in_hours?(schedule, dt) do dt diff --git a/lib/open_hours/schedule.ex b/lib/open_hours/schedule.ex index b9c9603..f64d375 100644 --- a/lib/open_hours/schedule.ex +++ b/lib/open_hours/schedule.ex @@ -94,7 +94,7 @@ defmodule OpenHours.Schedule do @spec in_hours?(OpenHours.Schedule.t(), DateTime.t()) :: boolean() def in_hours?(%Schedule{time_zone: schedule_tz} = schedule, %DateTime{time_zone: date_tz} = at) when schedule_tz != date_tz do - {:ok, shifted_at} = DateTime.shift_zone(at, schedule_tz, Tzdata.TimeZoneDatabase) + {:ok, shifted_at} = DateTime.shift_zone(at, schedule_tz, OpenHours.TimeZoneDatabase.database()) in_hours?(schedule, shifted_at) end diff --git a/lib/open_hours/time_slot.ex b/lib/open_hours/time_slot.ex index 8a87071..64b754d 100644 --- a/lib/open_hours/time_slot.ex +++ b/lib/open_hours/time_slot.ex @@ -25,7 +25,7 @@ defmodule OpenHours.TimeSlot do %DateTime{} = ends_at ) when schedule_tz != start_tz do - {:ok, shifted_starts_at} = DateTime.shift_zone(starts_at, schedule_tz, Tzdata.TimeZoneDatabase) + {:ok, shifted_starts_at} = DateTime.shift_zone(starts_at, schedule_tz, OpenHours.TimeZoneDatabase.database()) between(schedule, shifted_starts_at, ends_at) end @@ -35,7 +35,7 @@ defmodule OpenHours.TimeSlot do %DateTime{time_zone: end_tz} = ends_at ) when schedule_tz != end_tz do - {:ok, shifted_ends_at} = DateTime.shift_zone(ends_at, schedule_tz, Tzdata.TimeZoneDatabase) + {:ok, shifted_ends_at} = DateTime.shift_zone(ends_at, schedule_tz, OpenHours.TimeZoneDatabase.database()) between(schedule, starts_at, shifted_ends_at) end @@ -110,7 +110,7 @@ defmodule OpenHours.TimeSlot do def stream_next(%Schedule{time_zone: schedule_tz} = schedule, %DateTime{time_zone: dt_tz} = at, opts) when schedule_tz != dt_tz do - {:ok, shifted} = DateTime.shift_zone(at, schedule_tz, Tzdata.TimeZoneDatabase) + {:ok, shifted} = DateTime.shift_zone(at, schedule_tz, OpenHours.TimeZoneDatabase.database()) stream_next(schedule, shifted, opts) end @@ -158,7 +158,7 @@ defmodule OpenHours.TimeSlot do def stream_previous(%Schedule{time_zone: schedule_tz} = schedule, %DateTime{time_zone: dt_tz} = at, opts) when schedule_tz != dt_tz do - {:ok, shifted} = DateTime.shift_zone(at, schedule_tz, Tzdata.TimeZoneDatabase) + {:ok, shifted} = DateTime.shift_zone(at, schedule_tz, OpenHours.TimeZoneDatabase.database()) stream_previous(schedule, shifted, opts) end @@ -210,8 +210,8 @@ defmodule OpenHours.TimeSlot do |> get_intervals_for(day) |> Enum.map(fn {interval_start, interval_end} -> %TimeSlot{ - starts_at: DateTime.new!(day, interval_start, schedule.time_zone, Tzdata.TimeZoneDatabase), - ends_at: DateTime.new!(day, interval_end, schedule.time_zone, Tzdata.TimeZoneDatabase) + starts_at: DateTime.new!(day, interval_start, schedule.time_zone, OpenHours.TimeZoneDatabase.database()), + ends_at: DateTime.new!(day, interval_end, schedule.time_zone, OpenHours.TimeZoneDatabase.database()) } end) end diff --git a/lib/open_hours/time_zone_database.ex b/lib/open_hours/time_zone_database.ex new file mode 100644 index 0000000..133daaa --- /dev/null +++ b/lib/open_hours/time_zone_database.ex @@ -0,0 +1,21 @@ +defmodule OpenHours.TimeZoneDatabase do + @moduledoc """ + Resolves the configured `Calendar.TimeZoneDatabase` implementation. + + By default, the Elixir global time zone database is used (set via + `Calendar.put_time_zone_database/1`). You can override this for OpenHours + specifically by setting: + + config :open_hours, :time_zone_database, Tz.TimeZoneDatabase + + Any module that implements the `Calendar.TimeZoneDatabase` behaviour can be used. + """ + + @doc """ + Returns the configured time zone database module. + """ + @spec database() :: module() + def database do + Application.get_env(:open_hours, :time_zone_database, Calendar.get_time_zone_database()) + end +end diff --git a/mix.exs b/mix.exs index c380bb4..e61e95a 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule OpenHours.MixProject do use Mix.Project - @version "0.3.0" + @version "0.4.0" def project do [ @@ -19,14 +19,15 @@ defmodule OpenHours.MixProject do # Run "mix help compile.app" to learn about applications. def application do [ - extra_applications: [:logger, :tzdata] + extra_applications: [:logger] ] end # Run "mix help deps" to learn about dependencies. defp deps do [ - {:tzdata, "~> 1.1"}, + {:tzdata, "~> 1.1", optional: true}, + {:tz, "~> 0.28", optional: true}, {:ex_doc, "~> 0.31", only: :dev, runtime: false} ] end diff --git a/mix.lock b/mix.lock index 066b733..7d442ce 100644 --- a/mix.lock +++ b/mix.lock @@ -14,6 +14,7 @@ "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "rangex": {:git, "https://github.com/openapi-ro/rangex.git", "a92b03f8f075d73fef1bbbf4b1c088feaff8724b", [tag: "master"]}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, + "tz": {:hex, :tz, "0.28.2", "6c47f3d1a8ee5c33a1d8f0ba49e5a851b0a30c408a587d907aff6e71228b3b32", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "a6bf7355a33f0a7511602ab4566432ac0901d8abff81e94e455bca19708a0c87"}, "tzdata": {:hex, :tzdata, "1.1.3", "b1cef7bb6de1de90d4ddc25d33892b32830f907e7fc2fccd1e7e22778ab7dfbc", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "d4ca85575a064d29d4e94253ee95912edfb165938743dbf002acdf0dcecb0c28"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, } diff --git a/test/test_helper.exs b/test/test_helper.exs index 869559e..b9497e1 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1 +1,3 @@ +Application.put_env(:elixir, :time_zone_database, Tz.TimeZoneDatabase) + ExUnit.start()