Packages
tz_extra
0.28.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/compiler.ex
defmodule TzExtra.Compiler do
@moduledoc false
require TzExtra.IanaFileParser
import TzExtra.Helper
alias TzExtra.IanaFileParser
def compile() do
countries = IanaFileParser.countries()
time_zones = IanaFileParser.time_zones()
canonical_time_zones =
time_zones
|> Map.keys()
|> Enum.uniq()
|> Enum.sort()
all_time_zones =
time_zones
|> Enum.map(fn {canonical, links} -> [canonical | links] end)
|> List.flatten()
|> Enum.uniq()
|> Enum.sort()
link_canonical_map =
time_zones
|> Enum.reduce(%{}, fn {canonical, links}, map ->
Enum.reduce(links, map, fn link, map ->
Map.put(map, link, canonical)
end)
|> Map.put(canonical, canonical)
end)
get_time_zone_links_for_canonical_fun =
fn canonical ->
time_zones[canonical] |> Enum.sort()
end
countries_time_zones =
IanaFileParser.time_zones_with_country(countries)
|> add_time_zone_links(get_time_zone_links_for_canonical_fun)
|> add_offset_data()
|> localize_country_name()
|> Enum.sort_by(
&{&1.country && normalize_string(&1.country.name), &1.utc_offset, &1.time_zone}
)
civil_time_zones =
countries_time_zones
|> Enum.map(& &1.time_zone)
|> Enum.uniq()
|> Enum.sort()
civil_time_zones_with_links =
countries_time_zones
|> Enum.map(&[&1.time_zone | &1.time_zone_links])
|> List.flatten()
|> Enum.uniq()
|> Enum.sort()
quoted = [
for time_zone <- all_time_zones do
canonical_time_zone = link_canonical_map[time_zone]
countries_time_zones =
Enum.filter(countries_time_zones, &(&1.time_zone == canonical_time_zone))
if length(countries_time_zones) > 0 do
quote do
def for_time_zone(unquote(time_zone)) do
{:ok, unquote(Macro.escape(countries_time_zones))}
end
end
else
quote do
def for_time_zone(unquote(time_zone)) do
{:error, :time_zone_not_linked_to_country}
end
end
end
end,
quote do
def for_time_zone(_) do
{:error, :time_zone_not_found}
end
end,
for %{code: country_code} <- countries do
countries_time_zones =
Enum.filter(countries_time_zones, &(&1.country.code == country_code))
country_code_atom = String.to_atom(country_code)
quote do
def for_country_code(unquote(country_code)) do
{:ok, unquote(Macro.escape(countries_time_zones))}
end
def for_country_code(unquote(country_code_atom)) do
{:ok, unquote(Macro.escape(countries_time_zones))}
end
end
end,
quote do
def for_country_code(_) do
{:error, :country_not_found}
end
end
]
module = :"Elixir.TzExtra.CountryTimeZone"
Module.create(module, quoted, Macro.Env.location(__ENV__))
:code.purge(module)
contents = [
quote do
def iana_version() do
unquote(Tz.iana_version())
end
def get_canonical_time_zone_identifier(time_zone_identifier) do
unquote(Macro.escape(link_canonical_map))[time_zone_identifier] ||
raise "time zone identifier \"#{time_zone_identifier}\" not found"
end
def civil_time_zone_identifiers(opts \\ []) do
include_aliases = Keyword.get(opts, :include_aliases, false)
if include_aliases do
unquote(Macro.escape(civil_time_zones_with_links))
else
unquote(Macro.escape(civil_time_zones))
end
end
def time_zone_identifiers(opts \\ []) do
include_aliases = Keyword.get(opts, :include_aliases, false)
if include_aliases do
unquote(Macro.escape(all_time_zones))
else
unquote(Macro.escape(canonical_time_zones))
end
end
def countries_time_zones() do
unquote(Macro.escape(countries_time_zones))
end
def countries() do
unquote(Macro.escape(countries))
end
end
]
module = :"Elixir.TzExtra"
Module.create(module, contents, Macro.Env.location(__ENV__))
:code.purge(module)
end
# defp add_offset_data(time_zones) do
# %{
# coordinates: nil,
# country: nil,
# dst_offset: 0,
# dst_zone_abbr: "UTC",
# pretty_dst_offset: "+00:00",
# pretty_utc_offset: "+00:00",
# time_zone: "UTC",
# time_zone_links: [],
# utc_offset: 0,
# zone_abbr: "UTC"
# }
# end
defp add_offset_data(time_zones) do
Enum.map(time_zones, fn %{time_zone: time_zone_id} = time_zone ->
{:ok, periods} = Tz.PeriodsProvider.periods(time_zone_id)
{utc_offset, dst_offset, zone_abbr, dst_zone_abbr} =
case hd(periods) do
{_, {utc_offset, std_offset, zone_abbr}, _, nil} ->
{utc_offset, utc_offset + std_offset, zone_abbr, zone_abbr}
{_, {utc_offset, std_offset, zone_abbr}, {_, prev_std_offset, prev_zone_abbr}, _} ->
dst_offset = utc_offset + max(std_offset, prev_std_offset)
{zone_abbr, dst_zone_abbr} =
cond do
std_offset < prev_std_offset ->
{zone_abbr, prev_zone_abbr}
std_offset > prev_std_offset ->
{prev_zone_abbr, zone_abbr}
end
{utc_offset, dst_offset, zone_abbr, dst_zone_abbr}
end
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, zone_abbr)
|> Map.put(:dst_zone_abbr, dst_zone_abbr)
end)
end
defp add_time_zone_links(countries_time_zones, get_time_zone_links_for_canonical_fun) do
Enum.map(countries_time_zones, fn %{time_zone: time_zone_id} = time_zone ->
Map.put(
time_zone,
:time_zone_links,
get_time_zone_links_for_canonical_fun.(time_zone_id)
)
end)
end
defp localize_country_name(countries_time_zones) do
Enum.map(countries_time_zones, fn %{country: country} = time_zone ->
local_names = local_country_names(country.code)
%{time_zone | country: Map.put(country, :local_names, local_names)}
end)
end
defp local_country_names(country_code) do
local_countries_names =
%{
"AF" => ["افغانستان"],
"AX" => ["Åland"],
"AL" => ["Shqipëri"],
"DZ" => ["الجزائر"],
"AD" => ["Andorra"],
"AO" => ["Angola"],
"AI" => ["Anguilla"],
"AQ" => ["Antarctica"],
"AG" => ["Antigua & Barbuda"],
"AR" => ["Argentina"],
"AM" => ["Հայաստան"],
"AW" => ["Aruba"],
"AU" => ["Australia"],
"AT" => ["Österreich"],
"AZ" => ["Azərbaycan"],
"BS" => ["Bahamas"],
"BH" => ["البحرين"],
"BD" => ["বাংলাদেশ"],
"BB" => ["Barbados"],
"BY" => ["Беларусь"],
"BE" => ["België", "Belgique"],
"BZ" => ["Belize"],
"BJ" => ["Bénin"],
"BM" => ["Bermuda"],
"BT" => ["འབྲུག"],
"BO" => ["Bolivia", "Buliwya", "Wuliwya"],
"BA" => ["Bosna i Hercegovina"],
"BW" => ["Botswana"],
"BV" => ["Bouvetøya"],
"BR" => ["Brasil"],
"GB" => ["United Kingdom"],
"IO" => ["British Indian Ocean Territory"],
"BN" => ["Brunei"],
"BG" => ["България"],
"BF" => ["Burkina Faso"],
"BI" => ["Uburundi"],
"KH" => ["កម្ពុជា"],
"CM" => ["Cameroun", "Cameroon"],
"CA" => ["Canada"],
"CV" => ["Cabo Verde"],
"BQ" => ["Caribisch Nederland"],
"KY" => ["Cayman Islands"],
"CF" => ["Ködörösêse tî Bêafrîka"],
"TD" => ["Tchad", "تشاد"],
"CL" => ["Chile"],
"CN" => ["中国"],
"CX" => ["Christmas Island"],
"CC" => ["Cocos (Keeling) Islands"],
"CO" => ["Colombia"],
"KM" => ["Komori", "جزر القمر", "Comores"],
"CD" => ["République démocratique du Congo"],
"CG" => ["République du Congo"],
"CK" => ["Cook Islands"],
"CR" => ["Costa Rica"],
"CI" => ["Côte d'Ivoire"],
"HR" => ["Hrvatska"],
"CU" => ["Cuba"],
"CW" => ["Curaçao"],
"CY" => ["Κύπρος", "Kıbrıs"],
"CZ" => ["Česká republika"],
"DK" => ["Danmark"],
"DJ" => ["جيبوتي", "Djibouti"],
"DM" => ["Dominica"],
"DO" => ["República Dominicana"],
"TL" => ["Timor Lorosa'e"],
"EC" => ["Ecuador"],
"EG" => ["مصر"],
"SV" => ["El Salvador"],
"GQ" => ["Guinea Ecuatorial"],
"ER" => ["ኤርትራ", "إرتريا"],
"EE" => ["Eesti"],
"SZ" => ["Eswatini"],
"ET" => ["ኢትዮጵያ"],
"FK" => ["Falkland Islands"],
"FO" => ["Føroyar"],
"FJ" => ["Fiji"],
"FI" => ["Suomi"],
"FR" => ["France"],
"GF" => ["Guyane"],
"PF" => ["Polynésie française"],
"TF" => ["Terres australes et antarctiques françaises"],
"GA" => ["Gabon"],
"GM" => ["Gambia"],
"GE" => ["საქართველო"],
"DE" => ["Deutschland"],
"GH" => ["Ghana"],
"GI" => ["Gibraltar"],
"GR" => ["Ελλάδα"],
"GL" => ["Kalaallit Nunaat"],
"GD" => ["Grenada"],
"GP" => ["Guadeloupe"],
"GU" => ["Guåhån"],
"GT" => ["Guatemala"],
"GG" => ["Guernsey"],
"GN" => ["Guinée"],
"GW" => ["Guiné-Bissau"],
"GY" => ["Guyana"],
"HT" => ["Haïti", "Ayiti"],
"HM" => ["Heard Island & McDonald Islands"],
"HN" => ["Honduras"],
"HK" => ["香港"],
"HU" => ["Magyarország"],
"IS" => ["Ísland"],
"IN" => ["भारत", "Bharat", "இந்தியா"],
"ID" => ["Indonesia"],
"IR" => ["ایران"],
"IQ" => ["العراق"],
"IE" => ["Éire", "Ireland"],
"IM" => ["Ellan Vannin", "Isle of Man"],
"IL" => ["ישראל"],
"IT" => ["Italia"],
"JM" => ["Jamaica"],
"JP" => ["日本"],
"JE" => ["Jersey"],
"JO" => ["الأردن"],
"KZ" => ["Қазақстан", "Казахстан"],
"KE" => ["Kenya"],
"KI" => ["Kiribati"],
"KP" => ["조선"],
"KR" => ["한국"],
"KW" => ["الكويت"],
"KG" => ["Кыргызстан"],
"LA" => ["ລາວ"],
"LV" => ["Latvija"],
"LB" => ["لبنان"],
"LS" => ["Lesotho"],
"LR" => ["Liberia"],
"LY" => ["ليبيا"],
"LI" => ["Liechtenstein"],
"LT" => ["Lietuva"],
"LU" => ["Lëtzebuerg", "Luxembourg", "Luxemburg"],
"MO" => ["澳門", "Macau"],
"MG" => ["Madagasikara", "Madagascar"],
"MW" => ["Malawi"],
"MY" => ["Malaysia"],
"MV" => ["ދިވެހިރާއްޖޭގެ ޖުމްހޫރިއްޔާ"],
"ML" => ["Mali"],
"MT" => ["Malta"],
"MH" => ["M̧ajeļ", "Marshall Islands"],
"MQ" => ["Martinique"],
"MR" => ["موريتانيا"],
"MU" => ["Maurice", "Moris"],
"YT" => ["Mayotte"],
"MX" => ["México"],
"FM" => ["Micronesia"],
"MD" => ["Moldova"],
"MC" => ["Monaco"],
"MN" => ["Монгол улс"],
"ME" => ["Crna Gora", "Црна Гора"],
"MS" => ["Montserrat"],
"MA" => ["المغرب"],
"MZ" => ["Moçambique"],
"MM" => ["မြန်မာ"],
"NA" => ["Namibia"],
"NR" => ["Nauru"],
"NP" => ["नेपाल"],
"NL" => ["Nederland"],
"NC" => ["Nouvelle-Calédonie"],
"NZ" => ["New Zealand", "Aotearoa"],
"NI" => ["Nicaragua"],
"NE" => ["Niger"],
"NG" => ["Nigeria"],
"NU" => ["Niue"],
"NF" => ["Norfolk Island"],
"MK" => ["Северна Македонија"],
"MP" => ["Northern Mariana Islands"],
"NO" => ["Norge", "Noreg"],
"OM" => ["عمان"],
"PK" => ["پاکستان"],
"PW" => ["Palau"],
"PS" => ["فلسطين"],
"PA" => ["Panamá"],
"PG" => ["Papua Niugini", "Papua New Guinea"],
"PY" => ["Paraguay"],
"PE" => ["Perú"],
"PH" => ["Pilipinas"],
"PN" => ["Pitcairn"],
"PL" => ["Polska"],
"PT" => ["Portugal"],
"PR" => ["Puerto Rico"],
"QA" => ["قطر"],
"RE" => ["La Réunion"],
"RO" => ["România"],
"RU" => ["Россия"],
"RW" => ["Rwanda"],
"AS" => ["Amerika Samoa"],
"WS" => ["Samoa"],
"SM" => ["San Marino"],
"ST" => ["São Tomé e Príncipe"],
"SA" => ["السعودية"],
"SN" => ["Sénégal"],
"RS" => ["Србија"],
"SC" => ["Sesel", "Seychelles"],
"SL" => ["Sierra Leone"],
"SG" => ["新加坡", "சிங்கப்பூர்", "Singapore"],
"SK" => ["Slovensko"],
"SI" => ["Slovenija"],
"SB" => ["Solomon Islands"],
"SO" => ["Soomaaliya", "الصومال"],
"ZA" => ["South Africa", "Suid-Afrika", "Afrika Borwa"],
"GS" => ["South Georgia & the South Sandwich Islands"],
"SS" => ["جنوب السودان"],
"ES" => ["España"],
"LK" => ["ශ්රී ලංකා", "இலங்கை"],
"BL" => ["Saint-Barthélemy"],
"SH" => ["Saint Helena"],
"KN" => ["Saint Kitts & Nevis"],
"LC" => ["Saint Lucia"],
"SX" => ["Sint Maarten"],
"MF" => ["Saint-Martin"],
"PM" => ["Saint-Pierre et Miquelon"],
"VC" => ["Saint Vincent"],
"SD" => ["السودان"],
"SR" => ["Suriname"],
"SJ" => ["Svalbard og Jan Mayen"],
"SE" => ["Sverige"],
"CH" => ["Schweiz", "Suisse", "Svizzera"],
"SY" => ["سوريا"],
"TW" => ["臺灣"],
"TJ" => ["Тоҷикистон"],
"TZ" => ["Tanzania"],
"TH" => ["ไทย"],
"TG" => ["Togo"],
"TK" => ["Tokelau"],
"TO" => ["Tonga"],
"TT" => ["Trinidad & Tobago"],
"TN" => ["تونس"],
"TR" => ["Türkiye"],
"TM" => ["Türkmenistan"],
"TC" => ["Turks & Caicos Is"],
"TV" => ["Tuvalu"],
"UM" => ["US minor outlying islands"],
"UG" => ["Uganda"],
"UA" => ["Україна"],
"AE" => ["الإمارات"],
"US" => ["United States"],
"UY" => ["Uruguay"],
"UZ" => ["O'zbekiston"],
"VU" => ["Vanuatu"],
"VA" => ["Città del Vaticano", "Status Civitatis Vaticanæ"],
"VE" => ["Venezuela"],
"VN" => ["Việt Nam"],
"VG" => ["Virgin Islands"],
"VI" => ["Virgin Islands"],
"WF" => ["Wallis-et-Futuna"],
"EH" => ["الصحراء الغربية"],
"YE" => ["اليمن"],
"ZM" => ["Zambia"],
"ZW" => ["Zimbabwe"]
}
local_names = local_countries_names[country_code]
unless local_names do
raise "local country names not found for country #{country_code}"
end
local_names
end
end