Current section

Files

Jump to
tz_extra lib tz_extra.ex
Raw

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