]> Frank Brehm's Git Trees - pixelpark/pp-admin-tools.git/commitdiff
Adding lib/pp_admintools/tzlocal.py
authorFrank Brehm <frank.brehm@pixelpark.com>
Wed, 27 Mar 2024 10:56:55 +0000 (11:56 +0100)
committerFrank Brehm <frank.brehm@pixelpark.com>
Wed, 27 Mar 2024 10:56:55 +0000 (11:56 +0100)
lib/pp_admintools/tzlocal.py [new file with mode: 0644]

diff --git a/lib/pp_admintools/tzlocal.py b/lib/pp_admintools/tzlocal.py
new file mode 100644 (file)
index 0000000..df903c5
--- /dev/null
@@ -0,0 +1,1130 @@
+# -*- coding: utf-8 -*-
+"""
+@summary: A class for getting the local timezone as name or as a timezone object.
+
+@author: Frank Brehm
+@contact: frank.brehm@pixelpark.com
+@copyright: © 2024 by Frank Brehm, Berlin
+"""
+from __future__ import absolute_import
+
+# Standard modules
+import calendar
+import datetime
+import logging
+import os
+import re
+import time
+import warnings
+
+try:
+    import zoneinfo  # pragma: no cover
+except ImportError:
+    from backports import zoneinfo  # pragma: no cover
+
+# Own modules
+from .xlate import XLATOR
+
+_ = XLATOR.gettext
+ngettext = XLATOR.ngettext
+
+__version__ = '0.6.0'
+
+
+LOG = logging.getLogger(__name__)
+
+# =============================================================================
+TZ_NAMES_REVERSE = {
+    'AUS Central Standard Time': 'Australia/Darwin',
+    'AUS Eastern Standard Time': 'Australia/Sydney',
+    'Afghanistan Standard Time': 'Asia/Kabul',
+    'Alaskan Standard Time': 'America/Anchorage',
+    'Aleutian Standard Time': 'America/Adak',
+    'Altai Standard Time': 'Asia/Barnaul',
+    'Arab Standard Time': 'Asia/Riyadh',
+    'Arabian Standard Time': 'Asia/Dubai',
+    'Arabic Standard Time': 'Asia/Baghdad',
+    'Argentina Standard Time': 'America/Buenos_Aires',
+    'Astrakhan Standard Time': 'Europe/Astrakhan',
+    'Atlantic Standard Time': 'America/Halifax',
+    'Aus Central W. Standard Time': 'Australia/Eucla',
+    'Azerbaijan Standard Time': 'Asia/Baku',
+    'Azores Standard Time': 'Atlantic/Azores',
+    'Bahia Standard Time': 'America/Bahia',
+    'Bangladesh Standard Time': 'Asia/Dhaka',
+    'Belarus Standard Time': 'Europe/Minsk',
+    'Bougainville Standard Time': 'Pacific/Bougainville',
+    'Canada Central Standard Time': 'America/Regina',
+    'Cape Verde Standard Time': 'Atlantic/Cape_Verde',
+    'Caucasus Standard Time': 'Asia/Yerevan',
+    'Cen. Australia Standard Time': 'Australia/Adelaide',
+    'Central America Standard Time': 'America/Guatemala',
+    'Central Asia Standard Time': 'Asia/Almaty',
+    'Central Brazilian Standard Time': 'America/Cuiaba',
+    'Central Europe Standard Time': 'Europe/Budapest',
+    'Central European Standard Time': 'Europe/Warsaw',
+    'Central Pacific Standard Time': 'Pacific/Guadalcanal',
+    'Central Standard Time': 'America/Chicago',
+    'Central Standard Time (Mexico)': 'America/Mexico_City',
+    'Chatham Islands Standard Time': 'Pacific/Chatham',
+    'China Standard Time': 'Asia/Shanghai',
+    'Cuba Standard Time': 'America/Havana',
+    'Dateline Standard Time': 'Etc/GMT+12',
+    'E. Africa Standard Time': 'Africa/Nairobi',
+    'E. Australia Standard Time': 'Australia/Brisbane',
+    'E. Europe Standard Time': 'Europe/Chisinau',
+    'E. South America Standard Time': 'America/Sao_Paulo',
+    'Easter Island Standard Time': 'Pacific/Easter',
+    'Eastern Standard Time': 'America/New_York',
+    'Eastern Standard Time (Mexico)': 'America/Cancun',
+    'Egypt Standard Time': 'Africa/Cairo',
+    'Ekaterinburg Standard Time': 'Asia/Yekaterinburg',
+    'FLE Standard Time': 'Europe/Kiev',
+    'Fiji Standard Time': 'Pacific/Fiji',
+    'GMT Standard Time': 'Europe/London',
+    'GTB Standard Time': 'Europe/Bucharest',
+    'Georgian Standard Time': 'Asia/Tbilisi',
+    'Greenland Standard Time': 'America/Godthab',
+    'Greenwich Standard Time': 'Atlantic/Reykjavik',
+    'Haiti Standard Time': 'America/Port-au-Prince',
+    'Hawaiian Standard Time': 'Pacific/Honolulu',
+    'India Standard Time': 'Asia/Calcutta',
+    'Iran Standard Time': 'Asia/Tehran',
+    'Israel Standard Time': 'Asia/Jerusalem',
+    'Jordan Standard Time': 'Asia/Amman',
+    'Kaliningrad Standard Time': 'Europe/Kaliningrad',
+    'Korea Standard Time': 'Asia/Seoul',
+    'Libya Standard Time': 'Africa/Tripoli',
+    'Line Islands Standard Time': 'Pacific/Kiritimati',
+    'Lord Howe Standard Time': 'Australia/Lord_Howe',
+    'Magadan Standard Time': 'Asia/Magadan',
+    'Magallanes Standard Time': 'America/Punta_Arenas',
+    'Marquesas Standard Time': 'Pacific/Marquesas',
+    'Mauritius Standard Time': 'Indian/Mauritius',
+    'Middle East Standard Time': 'Asia/Beirut',
+    'Montevideo Standard Time': 'America/Montevideo',
+    'Morocco Standard Time': 'Africa/Casablanca',
+    'Mountain Standard Time': 'America/Denver',
+    'Mountain Standard Time (Mexico)': 'America/Mazatlan',
+    'Myanmar Standard Time': 'Asia/Rangoon',
+    'N. Central Asia Standard Time': 'Asia/Novosibirsk',
+    'Namibia Standard Time': 'Africa/Windhoek',
+    'Nepal Standard Time': 'Asia/Katmandu',
+    'New Zealand Standard Time': 'Pacific/Auckland',
+    'Newfoundland Standard Time': 'America/St_Johns',
+    'Norfolk Standard Time': 'Pacific/Norfolk',
+    'North Asia East Standard Time': 'Asia/Irkutsk',
+    'North Asia Standard Time': 'Asia/Krasnoyarsk',
+    'North Korea Standard Time': 'Asia/Pyongyang',
+    'Omsk Standard Time': 'Asia/Omsk',
+    'Pacific SA Standard Time': 'America/Santiago',
+    'Pacific Standard Time': 'America/Los_Angeles',
+    'Pacific Standard Time (Mexico)': 'America/Tijuana',
+    'Pakistan Standard Time': 'Asia/Karachi',
+    'Paraguay Standard Time': 'America/Asuncion',
+    'Qyzylorda Standard Time': 'Asia/Qyzylorda',
+    'Romance Standard Time': 'Europe/Paris',
+    'Russia Time Zone 10': 'Asia/Srednekolymsk',
+    'Russia Time Zone 11': 'Asia/Kamchatka',
+    'Russia Time Zone 3': 'Europe/Samara',
+    'Russian Standard Time': 'Europe/Moscow',
+    'SA Eastern Standard Time': 'America/Cayenne',
+    'SA Pacific Standard Time': 'America/Bogota',
+    'SA Western Standard Time': 'America/La_Paz',
+    'SE Asia Standard Time': 'Asia/Bangkok',
+    'Saint Pierre Standard Time': 'America/Miquelon',
+    'Sakhalin Standard Time': 'Asia/Sakhalin',
+    'Samoa Standard Time': 'Pacific/Apia',
+    'Sao Tome Standard Time': 'Africa/Sao_Tome',
+    'Saratov Standard Time': 'Europe/Saratov',
+    'Singapore Standard Time': 'Asia/Singapore',
+    'South Africa Standard Time': 'Africa/Johannesburg',
+    'South Sudan Standard Time': 'Africa/Juba',
+    'Sri Lanka Standard Time': 'Asia/Colombo',
+    'Sudan Standard Time': 'Africa/Khartoum',
+    'Syria Standard Time': 'Asia/Damascus',
+    'Taipei Standard Time': 'Asia/Taipei',
+    'Tasmania Standard Time': 'Australia/Hobart',
+    'Tocantins Standard Time': 'America/Araguaina',
+    'Tokyo Standard Time': 'Asia/Tokyo',
+    'Tomsk Standard Time': 'Asia/Tomsk',
+    'Tonga Standard Time': 'Pacific/Tongatapu',
+    'Transbaikal Standard Time': 'Asia/Chita',
+    'Turkey Standard Time': 'Europe/Istanbul',
+    'Turks And Caicos Standard Time': 'America/Grand_Turk',
+    'US Eastern Standard Time': 'America/Indianapolis',
+    'US Mountain Standard Time': 'America/Phoenix',
+    'UTC': 'Etc/UTC',
+    'UTC+12': 'Etc/GMT-12',
+    'UTC+13': 'Etc/GMT-13',
+    'UTC-02': 'Etc/GMT+2',
+    'UTC-08': 'Etc/GMT+8',
+    'UTC-09': 'Etc/GMT+9',
+    'UTC-11': 'Etc/GMT+11',
+    'Ulaanbaatar Standard Time': 'Asia/Ulaanbaatar',
+    'Venezuela Standard Time': 'America/Caracas',
+    'Vladivostok Standard Time': 'Asia/Vladivostok',
+    'Volgograd Standard Time': 'Europe/Volgograd',
+    'W. Australia Standard Time': 'Australia/Perth',
+    'W. Central Africa Standard Time': 'Africa/Lagos',
+    'W. Europe Standard Time': 'Europe/Berlin',
+    'W. Mongolia Standard Time': 'Asia/Hovd',
+    'West Asia Standard Time': 'Asia/Tashkent',
+    'West Bank Standard Time': 'Asia/Hebron',
+    'West Pacific Standard Time': 'Pacific/Port_Moresby',
+    'Yakutsk Standard Time': 'Asia/Yakutsk',
+    'Yukon Standard Time': 'America/Whitehorse',
+}
+
+TZ_NAMES = {
+    '': 'Central Standard Time (Mexico)',
+    'Africa/Abidjan': 'Greenwich Standard Time',
+    'Africa/Accra': 'Greenwich Standard Time',
+    'Africa/Addis_Ababa': 'E. Africa Standard Time',
+    'Africa/Algiers': 'W. Central Africa Standard Time',
+    'Africa/Asmara': 'E. Africa Standard Time',
+    'Africa/Asmera': 'E. Africa Standard Time',
+    'Africa/Bamako': 'Greenwich Standard Time',
+    'Africa/Bangui': 'W. Central Africa Standard Time',
+    'Africa/Banjul': 'Greenwich Standard Time',
+    'Africa/Bissau': 'Greenwich Standard Time',
+    'Africa/Blantyre': 'South Africa Standard Time',
+    'Africa/Brazzaville': 'W. Central Africa Standard Time',
+    'Africa/Bujumbura': 'South Africa Standard Time',
+    'Africa/Cairo': 'Egypt Standard Time',
+    'Africa/Casablanca': 'Morocco Standard Time',
+    'Africa/Ceuta': 'Romance Standard Time',
+    'Africa/Conakry': 'Greenwich Standard Time',
+    'Africa/Dakar': 'Greenwich Standard Time',
+    'Africa/Dar_es_Salaam': 'E. Africa Standard Time',
+    'Africa/Djibouti': 'E. Africa Standard Time',
+    'Africa/Douala': 'W. Central Africa Standard Time',
+    'Africa/El_Aaiun': 'Morocco Standard Time',
+    'Africa/Freetown': 'Greenwich Standard Time',
+    'Africa/Gaborone': 'South Africa Standard Time',
+    'Africa/Harare': 'South Africa Standard Time',
+    'Africa/Johannesburg': 'South Africa Standard Time',
+    'Africa/Juba': 'South Sudan Standard Time',
+    'Africa/Kampala': 'E. Africa Standard Time',
+    'Africa/Khartoum': 'Sudan Standard Time',
+    'Africa/Kigali': 'South Africa Standard Time',
+    'Africa/Kinshasa': 'W. Central Africa Standard Time',
+    'Africa/Lagos': 'W. Central Africa Standard Time',
+    'Africa/Libreville': 'W. Central Africa Standard Time',
+    'Africa/Lome': 'Greenwich Standard Time',
+    'Africa/Luanda': 'W. Central Africa Standard Time',
+    'Africa/Lubumbashi': 'South Africa Standard Time',
+    'Africa/Lusaka': 'South Africa Standard Time',
+    'Africa/Malabo': 'W. Central Africa Standard Time',
+    'Africa/Maputo': 'South Africa Standard Time',
+    'Africa/Maseru': 'South Africa Standard Time',
+    'Africa/Mbabane': 'South Africa Standard Time',
+    'Africa/Mogadishu': 'E. Africa Standard Time',
+    'Africa/Monrovia': 'Greenwich Standard Time',
+    'Africa/Nairobi': 'E. Africa Standard Time',
+    'Africa/Ndjamena': 'W. Central Africa Standard Time',
+    'Africa/Niamey': 'W. Central Africa Standard Time',
+    'Africa/Nouakchott': 'Greenwich Standard Time',
+    'Africa/Ouagadougou': 'Greenwich Standard Time',
+    'Africa/Porto-Novo': 'W. Central Africa Standard Time',
+    'Africa/Sao_Tome': 'Sao Tome Standard Time',
+    'Africa/Timbuktu': 'Greenwich Standard Time',
+    'Africa/Tripoli': 'Libya Standard Time',
+    'Africa/Tunis': 'W. Central Africa Standard Time',
+    'Africa/Windhoek': 'Namibia Standard Time',
+    'America/Adak': 'Aleutian Standard Time',
+    'America/Anchorage': 'Alaskan Standard Time',
+    'America/Anguilla': 'SA Western Standard Time',
+    'America/Antigua': 'SA Western Standard Time',
+    'America/Araguaina': 'Tocantins Standard Time',
+    'America/Argentina/Buenos_Aires': 'Argentina Standard Time',
+    'America/Argentina/Catamarca': 'Argentina Standard Time',
+    'America/Argentina/ComodRivadavia': 'Argentina Standard Time',
+    'America/Argentina/Cordoba': 'Argentina Standard Time',
+    'America/Argentina/Jujuy': 'Argentina Standard Time',
+    'America/Argentina/La_Rioja': 'Argentina Standard Time',
+    'America/Argentina/Mendoza': 'Argentina Standard Time',
+    'America/Argentina/Rio_Gallegos': 'Argentina Standard Time',
+    'America/Argentina/Salta': 'Argentina Standard Time',
+    'America/Argentina/San_Juan': 'Argentina Standard Time',
+    'America/Argentina/San_Luis': 'Argentina Standard Time',
+    'America/Argentina/Tucuman': 'Argentina Standard Time',
+    'America/Argentina/Ushuaia': 'Argentina Standard Time',
+    'America/Aruba': 'SA Western Standard Time',
+    'America/Asuncion': 'Paraguay Standard Time',
+    'America/Atikokan': 'SA Pacific Standard Time',
+    'America/Atka': 'Aleutian Standard Time',
+    'America/Bahia': 'Bahia Standard Time',
+    'America/Bahia_Banderas': 'Central Standard Time (Mexico)',
+    'America/Barbados': 'SA Western Standard Time',
+    'America/Belem': 'SA Eastern Standard Time',
+    'America/Belize': 'Central America Standard Time',
+    'America/Blanc-Sablon': 'SA Western Standard Time',
+    'America/Boa_Vista': 'SA Western Standard Time',
+    'America/Bogota': 'SA Pacific Standard Time',
+    'America/Boise': 'Mountain Standard Time',
+    'America/Buenos_Aires': 'Argentina Standard Time',
+    'America/Cambridge_Bay': 'Mountain Standard Time',
+    'America/Campo_Grande': 'Central Brazilian Standard Time',
+    'America/Cancun': 'Eastern Standard Time (Mexico)',
+    'America/Caracas': 'Venezuela Standard Time',
+    'America/Catamarca': 'Argentina Standard Time',
+    'America/Cayenne': 'SA Eastern Standard Time',
+    'America/Cayman': 'SA Pacific Standard Time',
+    'America/Chicago': 'Central Standard Time',
+    'America/Chihuahua': 'Central Standard Time (Mexico)',
+    'America/Ciudad_Juarez': 'Mountain Standard Time',
+    'America/Coral_Harbour': 'SA Pacific Standard Time',
+    'America/Cordoba': 'Argentina Standard Time',
+    'America/Costa_Rica': 'Central America Standard Time',
+    'America/Creston': 'US Mountain Standard Time',
+    'America/Cuiaba': 'Central Brazilian Standard Time',
+    'America/Curacao': 'SA Western Standard Time',
+    'America/Danmarkshavn': 'Greenwich Standard Time',
+    'America/Dawson': 'Yukon Standard Time',
+    'America/Dawson_Creek': 'US Mountain Standard Time',
+    'America/Denver': 'Mountain Standard Time',
+    'America/Detroit': 'Eastern Standard Time',
+    'America/Dominica': 'SA Western Standard Time',
+    'America/Edmonton': 'Mountain Standard Time',
+    'America/Eirunepe': 'SA Pacific Standard Time',
+    'America/El_Salvador': 'Central America Standard Time',
+    'America/Ensenada': 'Pacific Standard Time (Mexico)',
+    'America/Fort_Nelson': 'US Mountain Standard Time',
+    'America/Fort_Wayne': 'US Eastern Standard Time',
+    'America/Fortaleza': 'SA Eastern Standard Time',
+    'America/Glace_Bay': 'Atlantic Standard Time',
+    'America/Godthab': 'Greenland Standard Time',
+    'America/Goose_Bay': 'Atlantic Standard Time',
+    'America/Grand_Turk': 'Turks And Caicos Standard Time',
+    'America/Grenada': 'SA Western Standard Time',
+    'America/Guadeloupe': 'SA Western Standard Time',
+    'America/Guatemala': 'Central America Standard Time',
+    'America/Guayaquil': 'SA Pacific Standard Time',
+    'America/Guyana': 'SA Western Standard Time',
+    'America/Halifax': 'Atlantic Standard Time',
+    'America/Havana': 'Cuba Standard Time',
+    'America/Hermosillo': 'US Mountain Standard Time',
+    'America/Indiana/Indianapolis': 'US Eastern Standard Time',
+    'America/Indiana/Knox': 'Central Standard Time',
+    'America/Indiana/Marengo': 'US Eastern Standard Time',
+    'America/Indiana/Petersburg': 'Eastern Standard Time',
+    'America/Indiana/Tell_City': 'Central Standard Time',
+    'America/Indiana/Vevay': 'US Eastern Standard Time',
+    'America/Indiana/Vincennes': 'Eastern Standard Time',
+    'America/Indiana/Winamac': 'Eastern Standard Time',
+    'America/Indianapolis': 'US Eastern Standard Time',
+    'America/Inuvik': 'Mountain Standard Time',
+    'America/Iqaluit': 'Eastern Standard Time',
+    'America/Jamaica': 'SA Pacific Standard Time',
+    'America/Jujuy': 'Argentina Standard Time',
+    'America/Juneau': 'Alaskan Standard Time',
+    'America/Kentucky/Louisville': 'Eastern Standard Time',
+    'America/Kentucky/Monticello': 'Eastern Standard Time',
+    'America/Knox_IN': 'Central Standard Time',
+    'America/Kralendijk': 'SA Western Standard Time',
+    'America/La_Paz': 'SA Western Standard Time',
+    'America/Lima': 'SA Pacific Standard Time',
+    'America/Los_Angeles': 'Pacific Standard Time',
+    'America/Louisville': 'Eastern Standard Time',
+    'America/Lower_Princes': 'SA Western Standard Time',
+    'America/Maceio': 'SA Eastern Standard Time',
+    'America/Managua': 'Central America Standard Time',
+    'America/Manaus': 'SA Western Standard Time',
+    'America/Marigot': 'SA Western Standard Time',
+    'America/Martinique': 'SA Western Standard Time',
+    'America/Matamoros': 'Central Standard Time',
+    'America/Mazatlan': 'Mountain Standard Time (Mexico)',
+    'America/Mendoza': 'Argentina Standard Time',
+    'America/Menominee': 'Central Standard Time',
+    'America/Merida': 'Central Standard Time (Mexico)',
+    'America/Metlakatla': 'Alaskan Standard Time',
+    'America/Mexico_City': 'Central Standard Time (Mexico)',
+    'America/Miquelon': 'Saint Pierre Standard Time',
+    'America/Moncton': 'Atlantic Standard Time',
+    'America/Monterrey': 'Central Standard Time (Mexico)',
+    'America/Montevideo': 'Montevideo Standard Time',
+    'America/Montreal': 'Eastern Standard Time',
+    'America/Montserrat': 'SA Western Standard Time',
+    'America/Nassau': 'Eastern Standard Time',
+    'America/New_York': 'Eastern Standard Time',
+    'America/Nipigon': 'Eastern Standard Time',
+    'America/Nome': 'Alaskan Standard Time',
+    'America/Noronha': 'UTC-02',
+    'America/North_Dakota/Beulah': 'Central Standard Time',
+    'America/North_Dakota/Center': 'Central Standard Time',
+    'America/North_Dakota/New_Salem': 'Central Standard Time',
+    'America/Nuuk': 'Greenland Standard Time',
+    'America/Ojinaga': 'Central Standard Time',
+    'America/Panama': 'SA Pacific Standard Time',
+    'America/Pangnirtung': 'Eastern Standard Time',
+    'America/Paramaribo': 'SA Eastern Standard Time',
+    'America/Phoenix': 'US Mountain Standard Time',
+    'America/Port-au-Prince': 'Haiti Standard Time',
+    'America/Port_of_Spain': 'SA Western Standard Time',
+    'America/Porto_Acre': 'SA Pacific Standard Time',
+    'America/Porto_Velho': 'SA Western Standard Time',
+    'America/Puerto_Rico': 'SA Western Standard Time',
+    'America/Punta_Arenas': 'Magallanes Standard Time',
+    'America/Rainy_River': 'Central Standard Time',
+    'America/Rankin_Inlet': 'Central Standard Time',
+    'America/Recife': 'SA Eastern Standard Time',
+    'America/Regina': 'Canada Central Standard Time',
+    'America/Resolute': 'Central Standard Time',
+    'America/Rio_Branco': 'SA Pacific Standard Time',
+    'America/Rosario': 'Argentina Standard Time',
+    'America/Santa_Isabel': 'Pacific Standard Time (Mexico)',
+    'America/Santarem': 'SA Eastern Standard Time',
+    'America/Santiago': 'Pacific SA Standard Time',
+    'America/Santo_Domingo': 'SA Western Standard Time',
+    'America/Sao_Paulo': 'E. South America Standard Time',
+    'America/Scoresbysund': 'Azores Standard Time',
+    'America/Shiprock': 'Mountain Standard Time',
+    'America/Sitka': 'Alaskan Standard Time',
+    'America/St_Barthelemy': 'SA Western Standard Time',
+    'America/St_Johns': 'Newfoundland Standard Time',
+    'America/St_Kitts': 'SA Western Standard Time',
+    'America/St_Lucia': 'SA Western Standard Time',
+    'America/St_Thomas': 'SA Western Standard Time',
+    'America/St_Vincent': 'SA Western Standard Time',
+    'America/Swift_Current': 'Canada Central Standard Time',
+    'America/Tegucigalpa': 'Central America Standard Time',
+    'America/Thule': 'Atlantic Standard Time',
+    'America/Thunder_Bay': 'Eastern Standard Time',
+    'America/Tijuana': 'Pacific Standard Time (Mexico)',
+    'America/Toronto': 'Eastern Standard Time',
+    'America/Tortola': 'SA Western Standard Time',
+    'America/Vancouver': 'Pacific Standard Time',
+    'America/Virgin': 'SA Western Standard Time',
+    'America/Whitehorse': 'Yukon Standard Time',
+    'America/Winnipeg': 'Central Standard Time',
+    'America/Yakutat': 'Alaskan Standard Time',
+    'America/Yellowknife': 'Mountain Standard Time',
+    'Antarctica/Casey': 'Central Pacific Standard Time',
+    'Antarctica/Davis': 'SE Asia Standard Time',
+    'Antarctica/DumontDUrville': 'West Pacific Standard Time',
+    'Antarctica/Macquarie': 'Tasmania Standard Time',
+    'Antarctica/Mawson': 'West Asia Standard Time',
+    'Antarctica/McMurdo': 'New Zealand Standard Time',
+    'Antarctica/Palmer': 'SA Eastern Standard Time',
+    'Antarctica/Rothera': 'SA Eastern Standard Time',
+    'Antarctica/South_Pole': 'New Zealand Standard Time',
+    'Antarctica/Syowa': 'E. Africa Standard Time',
+    'Antarctica/Vostok': 'Central Asia Standard Time',
+    'Arctic/Longyearbyen': 'W. Europe Standard Time',
+    'Asia/Aden': 'Arab Standard Time',
+    'Asia/Almaty': 'Central Asia Standard Time',
+    'Asia/Amman': 'Jordan Standard Time',
+    'Asia/Anadyr': 'Russia Time Zone 11',
+    'Asia/Aqtau': 'West Asia Standard Time',
+    'Asia/Aqtobe': 'West Asia Standard Time',
+    'Asia/Ashgabat': 'West Asia Standard Time',
+    'Asia/Ashkhabad': 'West Asia Standard Time',
+    'Asia/Atyrau': 'West Asia Standard Time',
+    'Asia/Baghdad': 'Arabic Standard Time',
+    'Asia/Bahrain': 'Arab Standard Time',
+    'Asia/Baku': 'Azerbaijan Standard Time',
+    'Asia/Bangkok': 'SE Asia Standard Time',
+    'Asia/Barnaul': 'Altai Standard Time',
+    'Asia/Beirut': 'Middle East Standard Time',
+    'Asia/Bishkek': 'Central Asia Standard Time',
+    'Asia/Brunei': 'Singapore Standard Time',
+    'Asia/Calcutta': 'India Standard Time',
+    'Asia/Chita': 'Transbaikal Standard Time',
+    'Asia/Choibalsan': 'Ulaanbaatar Standard Time',
+    'Asia/Chongqing': 'China Standard Time',
+    'Asia/Chungking': 'China Standard Time',
+    'Asia/Colombo': 'Sri Lanka Standard Time',
+    'Asia/Dacca': 'Bangladesh Standard Time',
+    'Asia/Damascus': 'Syria Standard Time',
+    'Asia/Dhaka': 'Bangladesh Standard Time',
+    'Asia/Dili': 'Tokyo Standard Time',
+    'Asia/Dubai': 'Arabian Standard Time',
+    'Asia/Dushanbe': 'West Asia Standard Time',
+    'Asia/Famagusta': 'GTB Standard Time',
+    'Asia/Gaza': 'West Bank Standard Time',
+    'Asia/Harbin': 'China Standard Time',
+    'Asia/Hebron': 'West Bank Standard Time',
+    'Asia/Ho_Chi_Minh': 'SE Asia Standard Time',
+    'Asia/Hong_Kong': 'China Standard Time',
+    'Asia/Hovd': 'W. Mongolia Standard Time',
+    'Asia/Irkutsk': 'North Asia East Standard Time',
+    'Asia/Istanbul': 'Turkey Standard Time',
+    'Asia/Jakarta': 'SE Asia Standard Time',
+    'Asia/Jayapura': 'Tokyo Standard Time',
+    'Asia/Jerusalem': 'Israel Standard Time',
+    'Asia/Kabul': 'Afghanistan Standard Time',
+    'Asia/Kamchatka': 'Russia Time Zone 11',
+    'Asia/Karachi': 'Pakistan Standard Time',
+    'Asia/Kashgar': 'Central Asia Standard Time',
+    'Asia/Kathmandu': 'Nepal Standard Time',
+    'Asia/Katmandu': 'Nepal Standard Time',
+    'Asia/Khandyga': 'Yakutsk Standard Time',
+    'Asia/Kolkata': 'India Standard Time',
+    'Asia/Krasnoyarsk': 'North Asia Standard Time',
+    'Asia/Kuala_Lumpur': 'Singapore Standard Time',
+    'Asia/Kuching': 'Singapore Standard Time',
+    'Asia/Kuwait': 'Arab Standard Time',
+    'Asia/Macao': 'China Standard Time',
+    'Asia/Macau': 'China Standard Time',
+    'Asia/Magadan': 'Magadan Standard Time',
+    'Asia/Makassar': 'Singapore Standard Time',
+    'Asia/Manila': 'Singapore Standard Time',
+    'Asia/Muscat': 'Arabian Standard Time',
+    'Asia/Nicosia': 'GTB Standard Time',
+    'Asia/Novokuznetsk': 'North Asia Standard Time',
+    'Asia/Novosibirsk': 'N. Central Asia Standard Time',
+    'Asia/Omsk': 'Omsk Standard Time',
+    'Asia/Oral': 'West Asia Standard Time',
+    'Asia/Phnom_Penh': 'SE Asia Standard Time',
+    'Asia/Pontianak': 'SE Asia Standard Time',
+    'Asia/Pyongyang': 'North Korea Standard Time',
+    'Asia/Qatar': 'Arab Standard Time',
+    'Asia/Qostanay': 'Central Asia Standard Time',
+    'Asia/Qyzylorda': 'Qyzylorda Standard Time',
+    'Asia/Rangoon': 'Myanmar Standard Time',
+    'Asia/Riyadh': 'Arab Standard Time',
+    'Asia/Saigon': 'SE Asia Standard Time',
+    'Asia/Sakhalin': 'Sakhalin Standard Time',
+    'Asia/Samarkand': 'West Asia Standard Time',
+    'Asia/Seoul': 'Korea Standard Time',
+    'Asia/Shanghai': 'China Standard Time',
+    'Asia/Singapore': 'Singapore Standard Time',
+    'Asia/Srednekolymsk': 'Russia Time Zone 10',
+    'Asia/Taipei': 'Taipei Standard Time',
+    'Asia/Tashkent': 'West Asia Standard Time',
+    'Asia/Tbilisi': 'Georgian Standard Time',
+    'Asia/Tehran': 'Iran Standard Time',
+    'Asia/Tel_Aviv': 'Israel Standard Time',
+    'Asia/Thimbu': 'Bangladesh Standard Time',
+    'Asia/Thimphu': 'Bangladesh Standard Time',
+    'Asia/Tokyo': 'Tokyo Standard Time',
+    'Asia/Tomsk': 'Tomsk Standard Time',
+    'Asia/Ujung_Pandang': 'Singapore Standard Time',
+    'Asia/Ulaanbaatar': 'Ulaanbaatar Standard Time',
+    'Asia/Ulan_Bator': 'Ulaanbaatar Standard Time',
+    'Asia/Urumqi': 'Central Asia Standard Time',
+    'Asia/Ust-Nera': 'Vladivostok Standard Time',
+    'Asia/Vientiane': 'SE Asia Standard Time',
+    'Asia/Vladivostok': 'Vladivostok Standard Time',
+    'Asia/Yakutsk': 'Yakutsk Standard Time',
+    'Asia/Yangon': 'Myanmar Standard Time',
+    'Asia/Yekaterinburg': 'Ekaterinburg Standard Time',
+    'Asia/Yerevan': 'Caucasus Standard Time',
+    'Atlantic/Azores': 'Azores Standard Time',
+    'Atlantic/Bermuda': 'Atlantic Standard Time',
+    'Atlantic/Canary': 'GMT Standard Time',
+    'Atlantic/Cape_Verde': 'Cape Verde Standard Time',
+    'Atlantic/Faeroe': 'GMT Standard Time',
+    'Atlantic/Faroe': 'GMT Standard Time',
+    'Atlantic/Jan_Mayen': 'W. Europe Standard Time',
+    'Atlantic/Madeira': 'GMT Standard Time',
+    'Atlantic/Reykjavik': 'Greenwich Standard Time',
+    'Atlantic/South_Georgia': 'UTC-02',
+    'Atlantic/St_Helena': 'Greenwich Standard Time',
+    'Atlantic/Stanley': 'SA Eastern Standard Time',
+    'Australia/ACT': 'AUS Eastern Standard Time',
+    'Australia/Adelaide': 'Cen. Australia Standard Time',
+    'Australia/Brisbane': 'E. Australia Standard Time',
+    'Australia/Broken_Hill': 'Cen. Australia Standard Time',
+    'Australia/Canberra': 'AUS Eastern Standard Time',
+    'Australia/Currie': 'Tasmania Standard Time',
+    'Australia/Darwin': 'AUS Central Standard Time',
+    'Australia/Eucla': 'Aus Central W. Standard Time',
+    'Australia/Hobart': 'Tasmania Standard Time',
+    'Australia/LHI': 'Lord Howe Standard Time',
+    'Australia/Lindeman': 'E. Australia Standard Time',
+    'Australia/Lord_Howe': 'Lord Howe Standard Time',
+    'Australia/Melbourne': 'AUS Eastern Standard Time',
+    'Australia/NSW': 'AUS Eastern Standard Time',
+    'Australia/North': 'AUS Central Standard Time',
+    'Australia/Perth': 'W. Australia Standard Time',
+    'Australia/Queensland': 'E. Australia Standard Time',
+    'Australia/South': 'Cen. Australia Standard Time',
+    'Australia/Sydney': 'AUS Eastern Standard Time',
+    'Australia/Tasmania': 'Tasmania Standard Time',
+    'Australia/Victoria': 'AUS Eastern Standard Time',
+    'Australia/West': 'W. Australia Standard Time',
+    'Australia/Yancowinna': 'Cen. Australia Standard Time',
+    'Brazil/Acre': 'SA Pacific Standard Time',
+    'Brazil/DeNoronha': 'UTC-02',
+    'Brazil/East': 'E. South America Standard Time',
+    'Brazil/West': 'SA Western Standard Time',
+    'CST6CDT': 'Central Standard Time',
+    'Canada/Atlantic': 'Atlantic Standard Time',
+    'Canada/Central': 'Central Standard Time',
+    'Canada/Eastern': 'Eastern Standard Time',
+    'Canada/Mountain': 'Mountain Standard Time',
+    'Canada/Newfoundland': 'Newfoundland Standard Time',
+    'Canada/Pacific': 'Pacific Standard Time',
+    'Canada/Saskatchewan': 'Canada Central Standard Time',
+    'Canada/Yukon': 'Yukon Standard Time',
+    'Chile/Continental': 'Pacific SA Standard Time',
+    'Chile/EasterIsland': 'Easter Island Standard Time',
+    'Cuba': 'Cuba Standard Time',
+    'EST5EDT': 'Eastern Standard Time',
+    'Egypt': 'Egypt Standard Time',
+    'Eire': 'GMT Standard Time',
+    'Etc/GMT': 'UTC',
+    'Etc/GMT+0': 'UTC',
+    'Etc/GMT+1': 'Cape Verde Standard Time',
+    'Etc/GMT+10': 'Hawaiian Standard Time',
+    'Etc/GMT+11': 'UTC-11',
+    'Etc/GMT+12': 'Dateline Standard Time',
+    'Etc/GMT+2': 'UTC-02',
+    'Etc/GMT+3': 'SA Eastern Standard Time',
+    'Etc/GMT+4': 'SA Western Standard Time',
+    'Etc/GMT+5': 'SA Pacific Standard Time',
+    'Etc/GMT+6': 'Central America Standard Time',
+    'Etc/GMT+7': 'US Mountain Standard Time',
+    'Etc/GMT+8': 'UTC-08',
+    'Etc/GMT+9': 'UTC-09',
+    'Etc/GMT-0': 'UTC',
+    'Etc/GMT-1': 'W. Central Africa Standard Time',
+    'Etc/GMT-10': 'West Pacific Standard Time',
+    'Etc/GMT-11': 'Central Pacific Standard Time',
+    'Etc/GMT-12': 'UTC+12',
+    'Etc/GMT-13': 'UTC+13',
+    'Etc/GMT-14': 'Line Islands Standard Time',
+    'Etc/GMT-2': 'South Africa Standard Time',
+    'Etc/GMT-3': 'E. Africa Standard Time',
+    'Etc/GMT-4': 'Arabian Standard Time',
+    'Etc/GMT-5': 'West Asia Standard Time',
+    'Etc/GMT-6': 'Central Asia Standard Time',
+    'Etc/GMT-7': 'SE Asia Standard Time',
+    'Etc/GMT-8': 'Singapore Standard Time',
+    'Etc/GMT-9': 'Tokyo Standard Time',
+    'Etc/GMT0': 'UTC',
+    'Etc/Greenwich': 'UTC',
+    'Etc/UCT': 'UTC',
+    'Etc/UTC': 'UTC',
+    'Etc/Universal': 'UTC',
+    'Etc/Zulu': 'UTC',
+    'Europe/Amsterdam': 'W. Europe Standard Time',
+    'Europe/Andorra': 'W. Europe Standard Time',
+    'Europe/Astrakhan': 'Astrakhan Standard Time',
+    'Europe/Athens': 'GTB Standard Time',
+    'Europe/Belfast': 'GMT Standard Time',
+    'Europe/Belgrade': 'Central Europe Standard Time',
+    'Europe/Berlin': 'W. Europe Standard Time',
+    'Europe/Bratislava': 'Central Europe Standard Time',
+    'Europe/Brussels': 'Romance Standard Time',
+    'Europe/Bucharest': 'GTB Standard Time',
+    'Europe/Budapest': 'Central Europe Standard Time',
+    'Europe/Busingen': 'W. Europe Standard Time',
+    'Europe/Chisinau': 'E. Europe Standard Time',
+    'Europe/Copenhagen': 'Romance Standard Time',
+    'Europe/Dublin': 'GMT Standard Time',
+    'Europe/Gibraltar': 'W. Europe Standard Time',
+    'Europe/Guernsey': 'GMT Standard Time',
+    'Europe/Helsinki': 'FLE Standard Time',
+    'Europe/Isle_of_Man': 'GMT Standard Time',
+    'Europe/Istanbul': 'Turkey Standard Time',
+    'Europe/Jersey': 'GMT Standard Time',
+    'Europe/Kaliningrad': 'Kaliningrad Standard Time',
+    'Europe/Kiev': 'FLE Standard Time',
+    'Europe/Kirov': 'Russian Standard Time',
+    'Europe/Kyiv': 'FLE Standard Time',
+    'Europe/Lisbon': 'GMT Standard Time',
+    'Europe/Ljubljana': 'Central Europe Standard Time',
+    'Europe/London': 'GMT Standard Time',
+    'Europe/Luxembourg': 'W. Europe Standard Time',
+    'Europe/Madrid': 'Romance Standard Time',
+    'Europe/Malta': 'W. Europe Standard Time',
+    'Europe/Mariehamn': 'FLE Standard Time',
+    'Europe/Minsk': 'Belarus Standard Time',
+    'Europe/Monaco': 'W. Europe Standard Time',
+    'Europe/Moscow': 'Russian Standard Time',
+    'Europe/Nicosia': 'GTB Standard Time',
+    'Europe/Oslo': 'W. Europe Standard Time',
+    'Europe/Paris': 'Romance Standard Time',
+    'Europe/Podgorica': 'Central Europe Standard Time',
+    'Europe/Prague': 'Central Europe Standard Time',
+    'Europe/Riga': 'FLE Standard Time',
+    'Europe/Rome': 'W. Europe Standard Time',
+    'Europe/Samara': 'Russia Time Zone 3',
+    'Europe/San_Marino': 'W. Europe Standard Time',
+    'Europe/Sarajevo': 'Central European Standard Time',
+    'Europe/Saratov': 'Saratov Standard Time',
+    'Europe/Simferopol': 'Russian Standard Time',
+    'Europe/Skopje': 'Central European Standard Time',
+    'Europe/Sofia': 'FLE Standard Time',
+    'Europe/Stockholm': 'W. Europe Standard Time',
+    'Europe/Tallinn': 'FLE Standard Time',
+    'Europe/Tirane': 'Central Europe Standard Time',
+    'Europe/Tiraspol': 'E. Europe Standard Time',
+    'Europe/Ulyanovsk': 'Astrakhan Standard Time',
+    'Europe/Uzhgorod': 'FLE Standard Time',
+    'Europe/Vaduz': 'W. Europe Standard Time',
+    'Europe/Vatican': 'W. Europe Standard Time',
+    'Europe/Vienna': 'W. Europe Standard Time',
+    'Europe/Vilnius': 'FLE Standard Time',
+    'Europe/Volgograd': 'Volgograd Standard Time',
+    'Europe/Warsaw': 'Central European Standard Time',
+    'Europe/Zagreb': 'Central European Standard Time',
+    'Europe/Zaporozhye': 'FLE Standard Time',
+    'Europe/Zurich': 'W. Europe Standard Time',
+    'GB': 'GMT Standard Time',
+    'GB-Eire': 'GMT Standard Time',
+    'GMT+0': 'UTC',
+    'GMT-0': 'UTC',
+    'GMT0': 'UTC',
+    'Greenwich': 'UTC',
+    'Hongkong': 'China Standard Time',
+    'Iceland': 'Greenwich Standard Time',
+    'Indian/Antananarivo': 'E. Africa Standard Time',
+    'Indian/Chagos': 'Central Asia Standard Time',
+    'Indian/Christmas': 'SE Asia Standard Time',
+    'Indian/Cocos': 'Myanmar Standard Time',
+    'Indian/Comoro': 'E. Africa Standard Time',
+    'Indian/Kerguelen': 'West Asia Standard Time',
+    'Indian/Mahe': 'Mauritius Standard Time',
+    'Indian/Maldives': 'West Asia Standard Time',
+    'Indian/Mauritius': 'Mauritius Standard Time',
+    'Indian/Mayotte': 'E. Africa Standard Time',
+    'Indian/Reunion': 'Mauritius Standard Time',
+    'Iran': 'Iran Standard Time',
+    'Israel': 'Israel Standard Time',
+    'Jamaica': 'SA Pacific Standard Time',
+    'Japan': 'Tokyo Standard Time',
+    'Kwajalein': 'UTC+12',
+    'Libya': 'Libya Standard Time',
+    'MST7MDT': 'Mountain Standard Time',
+    'Mexico/BajaNorte': 'Pacific Standard Time (Mexico)',
+    'Mexico/BajaSur': 'Mountain Standard Time (Mexico)',
+    'Mexico/General': 'Central Standard Time (Mexico)',
+    'NZ': 'New Zealand Standard Time',
+    'NZ-CHAT': 'Chatham Islands Standard Time',
+    'Navajo': 'Mountain Standard Time',
+    'PRC': 'China Standard Time',
+    'PST8PDT': 'Pacific Standard Time',
+    'Pacific/Apia': 'Samoa Standard Time',
+    'Pacific/Auckland': 'New Zealand Standard Time',
+    'Pacific/Bougainville': 'Bougainville Standard Time',
+    'Pacific/Chatham': 'Chatham Islands Standard Time',
+    'Pacific/Chuuk': 'West Pacific Standard Time',
+    'Pacific/Easter': 'Easter Island Standard Time',
+    'Pacific/Efate': 'Central Pacific Standard Time',
+    'Pacific/Enderbury': 'UTC+13',
+    'Pacific/Fakaofo': 'UTC+13',
+    'Pacific/Fiji': 'Fiji Standard Time',
+    'Pacific/Funafuti': 'UTC+12',
+    'Pacific/Galapagos': 'Central America Standard Time',
+    'Pacific/Gambier': 'UTC-09',
+    'Pacific/Guadalcanal': 'Central Pacific Standard Time',
+    'Pacific/Guam': 'West Pacific Standard Time',
+    'Pacific/Honolulu': 'Hawaiian Standard Time',
+    'Pacific/Johnston': 'Hawaiian Standard Time',
+    'Pacific/Kanton': 'UTC+13',
+    'Pacific/Kiritimati': 'Line Islands Standard Time',
+    'Pacific/Kosrae': 'Central Pacific Standard Time',
+    'Pacific/Kwajalein': 'UTC+12',
+    'Pacific/Majuro': 'UTC+12',
+    'Pacific/Marquesas': 'Marquesas Standard Time',
+    'Pacific/Midway': 'UTC-11',
+    'Pacific/Nauru': 'UTC+12',
+    'Pacific/Niue': 'UTC-11',
+    'Pacific/Norfolk': 'Norfolk Standard Time',
+    'Pacific/Noumea': 'Central Pacific Standard Time',
+    'Pacific/Pago_Pago': 'UTC-11',
+    'Pacific/Palau': 'Tokyo Standard Time',
+    'Pacific/Pitcairn': 'UTC-08',
+    'Pacific/Pohnpei': 'Central Pacific Standard Time',
+    'Pacific/Ponape': 'Central Pacific Standard Time',
+    'Pacific/Port_Moresby': 'West Pacific Standard Time',
+    'Pacific/Rarotonga': 'Hawaiian Standard Time',
+    'Pacific/Saipan': 'West Pacific Standard Time',
+    'Pacific/Samoa': 'UTC-11',
+    'Pacific/Tahiti': 'Hawaiian Standard Time',
+    'Pacific/Tarawa': 'UTC+12',
+    'Pacific/Tongatapu': 'Tonga Standard Time',
+    'Pacific/Truk': 'West Pacific Standard Time',
+    'Pacific/Wake': 'UTC+12',
+    'Pacific/Wallis': 'UTC+12',
+    'Pacific/Yap': 'West Pacific Standard Time',
+    'Poland': 'Central European Standard Time',
+    'Portugal': 'GMT Standard Time',
+    'ROC': 'Taipei Standard Time',
+    'ROK': 'Korea Standard Time',
+    'Singapore': 'Singapore Standard Time',
+    'Turkey': 'Turkey Standard Time',
+    'UCT': 'UTC',
+    'US/Alaska': 'Alaskan Standard Time',
+    'US/Aleutian': 'Aleutian Standard Time',
+    'US/Arizona': 'US Mountain Standard Time',
+    'US/Central': 'Central Standard Time',
+    'US/Eastern': 'Eastern Standard Time',
+    'US/Hawaii': 'Hawaiian Standard Time',
+    'US/Indiana-Starke': 'Central Standard Time',
+    'US/Michigan': 'Eastern Standard Time',
+    'US/Mountain': 'Mountain Standard Time',
+    'US/Pacific': 'Pacific Standard Time',
+    'US/Samoa': 'UTC-11',
+    'UTC': 'UTC',
+    'Universal': 'UTC',
+    'W-SU': 'Russian Standard Time',
+    'Zulu': 'UTC',
+}
+
+CACHE_TZ = None
+CACHE_TZ_NAME = None
+
+RE_ZONE = re.compile(r'\s*ZONE\s*=\s*"')
+RE_TIMEZONE = re.compile(r'\s*TIMEZONE\s*=\s*"')
+RE_END = re.compile(r'"')
+
+# =============================================================================
+def get_tz_offset(tz):
+    """Get timezone's offset using built-in function datetime.utcoffset()."""
+    return int(datetime.datetime.now(tz).utcoffset().total_seconds())
+
+
+# =============================================================================
+def assert_tz_offset(tz, error=True):
+    """
+    Assert that system's timezone offset equals to the timezone offset found.
+
+    If they don't match, we probably have a misconfiguration, for example, an
+    incorrect timezone set in /etc/timezone file in systemd distributions.
+
+    If error is True, this method will raise a ValueError, otherwise it will
+    emit a warning.
+    """
+    tz_offset = get_tz_offset(tz)
+    system_offset = calendar.timegm(time.localtime()) - calendar.timegm(time.gmtime())
+    # No one has timezone offsets less than a minute, so this should be close enough:
+    if abs(tz_offset - system_offset) > 60:
+        msg = _(
+            'Timezone offset does not match system offset: {tz_offset} != {system_offset}. '
+            'Please, check your config files.'
+        ).format(tz_offset=tz_offset, system_offset=system_offset)
+        if error:
+            raise ValueError(msg)
+        warnings.warn(msg)
+
+
+# =============================================================================
+def _tz_name_from_env(tzenv=None):
+    if tzenv is None:
+        tzenv = os.environ.get('TZ')
+
+    if not tzenv:
+        return None
+
+    LOG.debug(_('Found a TZ environment: {}').format(tzenv))
+
+    if tzenv[0] == ':':
+        tzenv = tzenv[1:]
+
+    if tzenv in TZ_NAMES:
+        # Yup, it's a timezone
+        return tzenv
+
+    if os.path.isabs(tzenv) and os.path.exists(tzenv):
+        # It's a file specification, expand it, if possible
+        parts = os.path.realpath(tzenv).split(os.sep)
+
+        # Is it a zone info zone?
+        possible_tz = '/'.join(parts[-2:])
+        if possible_tz in TZ_NAMES:
+            # Yup, it is
+            return possible_tz
+
+        # Maybe it's a short one, like UTC?
+        if parts[-1] in TZ_NAMES:
+            # Indeed
+            return parts[-1]
+
+    LOG.debug(_('Environment variable TZ does not contain a time zone name.'))
+    return None
+
+
+# =============================================================================
+def _tz_from_env(tzenv=None):
+    if tzenv is None:
+        tzenv = os.environ.get('TZ')
+
+    if not tzenv:
+        return None
+
+    # Some weird format that exists:
+    if tzenv[0] == ':':
+        tzenv = tzenv[1:]
+
+    # TZ specifies a file
+    if os.path.isabs(tzenv) and os.path.exists(tzenv):
+        # Try to see if we can figure out the name
+        tzname = _tz_name_from_env(tzenv)
+        if not tzname:
+            # Nope, not a standard timezone name, just take the filename
+            tzname = tzenv.split(os.sep)[-1]
+        with open(tzenv, 'rb') as tzfile:
+            return zoneinfo.ZoneInfo.from_file(tzfile, key=tzname)
+
+    # TZ must specify a zoneinfo zone.
+    try:
+        tz = zoneinfo.ZoneInfo(tzenv)
+        # That worked, so we return this:
+        return tz
+    except zoneinfo.ZoneInfoNotFoundError:
+        # Nope, it's something like "PST4DST" etc, we can't handle that.
+        msg = _('tzlocal() does not support non-zoneinfo timezones like {!r}.').format(tzenv)
+        msg += '\n' + _('Please use a timezone in the form of Continent/City.')
+        raise zoneinfo.ZoneInfoNotFoundError(msg) from None
+
+
+# ==============================================================================
+def _read_android_tz():
+    LOG.debug(_('This looks like {}.').format('Termux'))
+
+    import subprocess
+
+    try:
+        androidtz = (
+            subprocess.check_output(['getprop', 'persist.sys.timezone'])
+            .strip()
+            .decode()
+        )
+        return androidtz
+    except (OSError, subprocess.CalledProcessError):
+        # proot environment or failed to getprop
+        LOG.debug(_("It's not {}?").format('Termux'))
+
+    return None
+
+
+# ==============================================================================
+def _read_etc_timezone(tzpath):
+    try:
+        with open(tzpath) as tzfile:
+            data = tzfile.read()
+            LOG.debug(_('{!r} found, contents:').format(tzpath) + '\n' + data)
+
+            etctz = data.strip('/ \t\r\n')
+            if not etctz:
+                # Empty file, skip
+                return None
+
+            for etctz in etctz.splitlines():
+                # Get rid of host definitions and comments:
+                if ' ' in etctz:
+                    etctz, dummy = etctz.split(' ', 1)
+                if '#' in etctz:
+                    etctz, dummy = etctz.split('#', 1)
+                if not etctz:
+                    continue
+
+                return etctz.replace(' ', '_')
+
+    except (OSError, UnicodeDecodeError):
+        # File doesn't exist or is a directory, or it's a binary file.
+        return None
+
+    return None
+
+
+# =============================================================================
+def _read_clock_timezone(tzpath):
+    try:
+        with open(tzpath, 'rt') as tzfile:
+            data = tzfile.readlines()
+            LOG.debug(_('{!r} found, contents:').format(tzpath) + '\n' + data)
+
+        for line in data:
+            # Look for the ZONE= setting.
+            match = RE_ZONE.match(line)
+            if match is None:
+                # No ZONE= setting. Look for the TIMEZONE= setting.
+                match = RE_TIMEZONE.match(line)
+            if match is not None:
+                # Some setting existed
+                line = line[match.end():]
+                etctz = line[: RE_END.search(line).start()]
+
+                # We found a timezone
+                return etctz.replace(' ', '_')
+
+    except (OSError, UnicodeDecodeError):
+        # UnicodeDecode handles when clock is symlink to /etc/localtime
+        return None
+
+    return None
+
+
+# =============================================================================
+def _get_localzone_name(_root='/'):
+    """
+    Try to find the local timezone configuration.
+
+    This method finds the timezone name, if it can, or it returns None.
+
+    The parameter _root makes the function look for files like /etc/localtime
+    beneath the _root directory. This is primarily used by the tests.
+    In normal usage you call the function without parameters.
+    """
+    # First try the ENV setting.
+    tzenv = _tz_name_from_env()
+    if tzenv:
+        return tzenv
+
+    # Are we under Termux on Android?
+    if os.path.exists(os.path.join(_root, 'system/bin/getprop')):
+        return _read_android_tz()
+
+    # Now look for distribution specific configuration files
+    # that contain the timezone name.
+
+    # Stick all of them in a dict, to compare later.
+    found_configs = {}
+
+    for configfile in ('etc/timezone', 'var/db/zoneinfo'):
+        tzpath = os.path.join(_root, configfile)
+        tzconfig = _read_etc_timezone(tzpath)
+        if tzconfig is not None:
+            found_configs[tzpath] = tzconfig
+
+    # CentOS has a ZONE setting in /etc/sysconfig/clock,
+    # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and
+    # Gentoo has a TIMEZONE setting in /etc/conf.d/clock
+    # We look through these files for a timezone:
+
+    for filename in ('etc/sysconfig/clock', 'etc/conf.d/clock'):
+        tzpath = os.path.join(_root, filename)
+        tzconfig = _read_clock_timezone(tzpath)
+        if tzconfig is not None:
+            found_configs[tzpath] = tzconfig
+
+    # systemd distributions use symlinks that include the zone name,
+    # see manpage of localtime(5) and timedatectl(1)
+    tzpath = os.path.join(_root, 'etc/localtime')
+    if os.path.exists(tzpath) and os.path.islink(tzpath):
+        LOG.debug(_('{!r} found.').format(tzpath))
+        etctz = os.path.realpath(tzpath)
+        start = etctz.find('/') + 1
+        while start != 0:
+            etctz = etctz[start:]
+            try:
+                zoneinfo.ZoneInfo(etctz)
+                tzinfo = f'{tzpath} is a symlink to'
+                found_configs[tzinfo] = etctz.replace(' ', '_')
+                # Only need first valid relative path in simlink.
+                break
+            except zoneinfo.ZoneInfoNotFoundError:
+                pass
+            start = etctz.find('/') + 1
+
+    if len(found_configs) > 0:
+        msg = _('{} found:').format(len(found_configs)) + '\n' + found_configs
+        LOG.debug(msg)
+        # We found some explicit config of some sort!
+        if len(found_configs) > 1:
+            # Uh-oh, multiple configs. See if they match:
+            unique_tzs = set()
+            zoneinfopath = os.path.join(_root, 'usr', 'share', 'zoneinfo')
+            directory_depth = len(zoneinfopath.split(os.path.sep))
+
+            for tzname in found_configs.values():
+                # Look them up in /usr/share/zoneinfo, and find what they
+                # really point to:
+                path = os.path.realpath(os.path.join(zoneinfopath, *tzname.split('/')))
+                real_zone_name = '/'.join(path.split(os.path.sep)[directory_depth:])
+                unique_tzs.add(real_zone_name)
+
+            if len(unique_tzs) != 1:
+                message = _('Multiple conflicting time zone configurations found:') + '\n'
+                for key, value in found_configs.items():
+                    message += f'{key}: {value}\n'
+                message += _(
+                    'Fix the configuration, or set the time zone in a TZ environment '
+                    'variable.') + '\n'
+                raise zoneinfo.ZoneInfoNotFoundError(message)
+
+        # We found exactly one config! Use it.
+        return list(found_configs.values())[0]
+
+
+# =============================================================================
+def _get_localzone(_root='/'):
+    """
+    Create a timezone object from the timezone name.
+
+    If there is no timezone config, it will try to create a file from the
+    localtime timezone, and if there isn't one, it will default to UTC.
+
+    The parameter _root makes the function look for files like /etc/localtime
+    beneath the _root directory. This is primarily used by the tests.
+    In normal usage you call the function without parameters.
+    """
+    # First try the ENV setting.
+    tzenv = _tz_from_env()
+    if tzenv:
+        return tzenv
+
+    tzname = _get_localzone_name(_root)
+    if tzname is None:
+        # No explicit setting existed. Use localtime
+        LOG.debug(_('No explicit setting existed. Use localtime".'))
+        for filename in ('etc/localtime', 'usr/local/etc/localtime'):
+            tzpath = os.path.join(_root, filename)
+
+            if not os.path.exists(tzpath):
+                continue
+            with open(tzpath, 'rb') as tzfile:
+                tz = zoneinfo.ZoneInfo.from_file(tzfile, key='local')
+                break
+        else:
+            warnings.warn(_('Can not find any timezone configuration, defaulting to UTC.'))
+            tz = datetime.timezone.utc
+    else:
+        tz = zoneinfo.ZoneInfo(tzname)
+
+    if _root == '/':
+        # We are using a file in etc to name the timezone.
+        # Verify that the timezone specified there is actually used:
+        assert_tz_offset(tz, error=False)
+    return tz
+
+
+# =============================================================================
+def get_localzone_name():
+    """Get the computers configured local timezone name, if any."""
+    global CACHE_TZ_NAME
+
+    if CACHE_TZ_NAME is None:
+        CACHE_TZ_NAME = _get_localzone_name()
+
+    return CACHE_TZ_NAME
+
+
+# =============================================================================
+def get_localzone():
+    """Get the computers configured local timezone, if any."""
+    global CACHE_TZ
+
+    if CACHE_TZ is None:
+        CACHE_TZ = _get_localzone()
+
+    return CACHE_TZ
+
+
+# =============================================================================
+def reload_localzone():
+    """Reload the cached localzone. You need to call this if the timezone has changed."""
+    global CACHE_TZ_NAME
+    global CACHE_TZ
+
+    CACHE_TZ_NAME = _get_localzone_name()
+    CACHE_TZ = _get_localzone()
+
+    return CACHE_TZ
+
+
+# =============================================================================
+
+if __name__ == '__main__':
+
+    pass
+
+# =============================================================================
+
+# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list