Packages
tz_extra
0.2.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.1
0.22.0
0.21.1
0.21.0
0.20.1
0.20.0
0.17.0
0.16.7
0.16.6
0.16.5
0.16.3
0.16.2
0.16.1
0.16.0
0.15.1
0.15.0
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
Time zone-related utilities
Current section
Files
Jump to
Current section
Files
lib/tz_extra.ex
defmodule TzExtra do
require TzExtra.FileParser.CountryParser
require TzExtra.FileParser.ZoneParser
require TzExtra.FileParser.ZoneRuleParser
import TzExtra.Helper
alias TzExtra.FileParser.CountryParser
alias TzExtra.FileParser.ZoneParser
alias TzExtra.FileParser.ZoneRuleParser
tz_data_dir = Path.join(:code.priv_dir(:tz), Tz.version())
countries = CountryParser.parse(Path.join(tz_data_dir, "iso3166.tab"))
time_zones_with_country = ZoneParser.parse(Path.join(tz_data_dir, "zone1970.tab"), countries)
time_zones_with_country = [%{coordinates: nil, country: nil, name: "Etc/UTC", short_name: "UTC"} | time_zones_with_country]
time_zones_with_country =
Enum.map(time_zones_with_country, fn time_zone ->
{:ok, periods} = Tz.periods(time_zone.name)
utc_offset = find_latest_utc_offset_for_periods(periods)
dst_offset = utc_offset + find_latest_std_offset_for_periods(periods)
time_zone
|> Map.put(:utc_offset, utc_offset)
|> Map.put(:dst_offset, dst_offset)
|> Map.put(:pretty_utc_offset, offset_to_string(utc_offset))
|> Map.put(:pretty_dst_offset, offset_to_string(dst_offset))
|> Map.put(:zone_abbr, find_zone_abbr_for_periods(periods))
|> Map.put(:dst_zone_abbr, find_dst_zone_abbr_for_periods(periods))
end)
all_time_zones =
for filename <- ~w(africa antarctica asia australasia backward etcetera europe northamerica southamerica)s do
ZoneRuleParser.parse(Path.join(tz_data_dir, filename))
end
|> List.flatten()
|> Enum.filter(fn
%{record_type: :link, canonical_zone_name: "Etc/GMT"} ->
false
%{record_type: :link, canonical_zone_name: "Etc/UTC"} ->
false
%{name: name} ->
!String.contains?(name, "GMT") && String.contains?(name, "/")
_ ->
true
end)
time_zones =
Enum.map(all_time_zones, fn
%{record_type: :link} = time_zone ->
filtered_time_zones_with_country = Enum.filter(time_zones_with_country, & &1.name == time_zone.link_zone_name)
if Enum.count(filtered_time_zones_with_country) == 0 do
filtered_time_zones_with_country = Enum.filter(time_zones_with_country, & &1.name == time_zone.canonical_zone_name)
if Enum.count(filtered_time_zones_with_country) == 0 do
raise "missing time zone in zone1970.tab file: #{time_zone.canonical_zone_name}"
end
for filtered_time_zone_with_country <- filtered_time_zones_with_country do
filtered_time_zone_with_country
|> Map.put(:name, time_zone.link_zone_name)
|> Map.put(:short_name, String.split(time_zone.link_zone_name, "/") |> List.last())
|> Map.put(:link, time_zone.canonical_zone_name)
end
else
filtered_time_zones_with_country
end
time_zone ->
filtered_time_zones_with_country = Enum.filter(time_zones_with_country, & &1.name == time_zone.name)
if Enum.count(filtered_time_zones_with_country) == 0 do
raise "missing time zone in zone1970.tab file: #{time_zone.name}"
end
for filtered_time_zone_with_country <- filtered_time_zones_with_country do
filtered_time_zone_with_country
|> Map.put(:link, nil)
end
end)
|> List.flatten()
|> Enum.filter(& &1 != nil)
|> Enum.sort_by(&{&1.country && &1.country.name, &1.utc_offset, &1.name})
time_zones_without_links = Enum.filter(time_zones, & &1.link == nil)
def time_zones(opts \\ [])
def time_zones(with_links: false) do
unquote(Macro.escape(time_zones_without_links))
end
def time_zones(_) do
unquote(Macro.escape(time_zones))
end
def countries() do
unquote(Macro.escape(countries))
end
end