Tz - time zone support for Elixir (alternative to Tzdata that comes with a lot of bugfixes)

@mathieuprog I want to run Datetime.shift_zone/2 using “Pacific/Auckland” time zone. The thing is that in the current month (November) they increase their time by one our for daylight saving purposes:

%{
  coordinates: "-3652+17446",
  country: %{code: "NZ", name: "New Zealand"},
  dst_offset: 46800,
  dst_zone_abbr: "NZDT",
  pretty_dst_offset: "+13:00",
  pretty_utc_offset: "+12:00",
  time_zone: "Pacific/Auckland",
  time_zone_links: [],
  utc_offset: 43200,
  zone_abbr: "NZST"
}

Should I always use the dst_offset in case any other country has DST too? Also, suppose we are in a month where the DST ended, the dst_offset for New Zealand will be the same as the utc_offset?

This is the function I use to convert a NaiveDateTime to a DateTime with a specific time_zone:

def shift_time_based_on_timezone(%NaiveDateTime{} = naive, timezone) do
  datetime = DateTime.from_naive!(naive, timezone)
  DateTime.add(datetime, datetime.utc_offset, :second)
end

PS: thanks for your fast response in my other reply.

UPDATE

I’ve changed my function as follows and now I’m getting the right converted time:

defp shift_time_based_on_timezone(%NaiveDateTime{} = naive, timezone) do
  datetime = DateTime.from_naive!(naive, timezone)
  offset = datetime.utc_offset + datetime.std_offset # Added this line
  DateTime.add(datetime, offset, :second)
end

I think we first need to know what the naive datetime is representing in your system, where does it come from, … because a naive datetime is just a date and time without any time zone related data. Normally you wouldn’t need to perform such operations on a naive datetime.

Version 0.24 has been released!

The lib is close to reach a 1.0 version now.

Recent work includes:

  • Improved the Readme with an index:
    GitHub - mathieuprog/tz: Time zone support for Elixir :sparkles:

  • Added a Changelog file

  • Change option names:
    — :reject_time_zone_periods_before_year to :reject_periods_before_year
    — :build_time_zone_periods_with_ongoing_dst_changes_until_year to :build_dst_periods_until_year
    (usage of unknown option names raises an error at compile time)

  • Added a mix task to download the IANA time zone data

  • Added some configuration options for the schedulers updating and watching time zone data (frequency of the updates and user callback when update found)

  • Handle some edge cases (negative year and non-iso dates)

  • Fix warnings with more recent versions of Elixir

  • Fix Dialyzer warnings

  • Fix some bugs related to config

4 Likes

The repo tzdb_test compares the result of time zone operations on some ~10 million date times.

From the readme:

At the time of writing this,

  • the output of Java, tz and time_zone_info is identical;
  • tzdata generates a lot of wrong dates;
  • zoneinfo generates wrong dates for some special time zones and for dates in the year 2038.

The time taken for each library to generate the output on my system are:

  • ~50 seconds for tz
  • ~50 seconds for time_zone_info
  • ~80 seconds for zoneinfo
  • ~160 seconds for tzdata
2 Likes

The new IANA tzdata 2023a update made the compilation raise an error.

This happened because the updated rules for Palestine introduced a new unexpected edge case.

The issue has been resolved in version 0.25.0

6 Likes

3 Likes

I am using timex which depends on tzdata. Are you aware of any replacement that depends on tz instead?

You may simply rely on the core Elixir date/time modules instead of Timex today as the former evolved and improved significantly since Timex was released.

6 Likes