Packages
tz_extra
0.6.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/iana_file_parser.ex
defmodule TzExtra.IanaFileParser do
@moduledoc false
import TzExtra.Helper
def countries() do
Path.join([:code.priv_dir(:tz), "tzdata#{Tz.version()}", "iso3166.tab"])
|> file_to_list()
|> parse_countries()
|> Enum.sort_by(&normalize_string(&1.name))
end
def time_zones_with_country(countries) do
Path.join([:code.priv_dir(:tz), "tzdata#{Tz.version()}", "zone1970.tab"])
|> file_to_list()
|> parse_time_zones_with_country()
|> Enum.map(fn map ->
{country_code, map} = pop_in(map, [:country_code])
country = Enum.find(countries, & &1.code == country_code)
Map.put(map, :country, country)
end)
end
def link_time_zones() do
for filename <- ~w(africa antarctica asia australasia backward etcetera europe northamerica southamerica)s do
Path.join([:code.priv_dir(:tz), "tzdata#{Tz.version()}", filename])
|> file_to_list()
|> parse_link_time_zones()
end
|> List.flatten()
end
defp file_to_list(file_path) do
File.stream!(file_path)
|> strip_comments()
|> strip_empty()
|> trim()
|> Enum.to_list()
end
defp strip_comments(stream) do
stream
|> Stream.filter(&(!Regex.match?(~r/^[\s]*#/, &1)))
|> Stream.map(&Regex.replace(~r/[\s]*#.+/, &1, ""))
end
defp strip_empty(stream) do
Stream.filter(stream, &(!Regex.match?(~r/^[\s]*\n$/, &1)))
end
defp trim(stream) do
Stream.map(stream, &String.trim(&1))
end
defp parse_countries([]), do: []
defp parse_countries([string | tail]) do
map =
Enum.zip([
[:code, :name],
String.split(string, ~r{\s}, trim: true, parts: 2)
|> Enum.map(& String.trim(&1))
])
|> Enum.into(%{})
[map | parse_countries(tail)]
end
defp parse_link_time_zones([]), do: []
defp parse_link_time_zones([string | tail]) do
if String.starts_with?(string, "Link") do
link =
Enum.zip([
[:canonical_zone_name, :link_zone_name],
tl(String.split(string, ~r{\s}, trim: true, parts: 3))
|> Enum.map(& String.trim(&1))
])
|> Enum.into(%{})
[link | parse_link_time_zones(tail)]
else
parse_link_time_zones(tail)
end
end
defp parse_time_zones_with_country([]), do: []
defp parse_time_zones_with_country([string | tail]) do
map =
Enum.zip([
[:country_codes, :coordinates, :time_zone, :_],
String.split(string, ~r{\s}, trim: true, parts: 4)
|> Enum.map(& String.trim(&1))
])
|> Enum.into(%{})
|> Map.delete(:_)
country_codes = String.split(map.country_codes, ",", trim: true)
for country_code <- country_codes do
%{
country_code: country_code,
coordinates: map.coordinates,
time_zone: map.time_zone
}
end
++ parse_time_zones_with_country(tail)
end
end