diff options
Diffstat (limited to 'venv/lib/python3.9/site-packages/tzlocal/utils.py')
-rw-r--r-- | venv/lib/python3.9/site-packages/tzlocal/utils.py | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/venv/lib/python3.9/site-packages/tzlocal/utils.py b/venv/lib/python3.9/site-packages/tzlocal/utils.py new file mode 100644 index 00000000..5aca1936 --- /dev/null +++ b/venv/lib/python3.9/site-packages/tzlocal/utils.py @@ -0,0 +1,127 @@ +import os +import time +import datetime +import calendar +import pytz_deprecation_shim as pds + +try: + import zoneinfo # pragma: no cover +except ImportError: + from backports import zoneinfo # pragma: no cover + +from tzlocal import windows_tz + + +class ZoneInfoNotFoundError(pds.UnknownTimeZoneError, zoneinfo.ZoneInfoNotFoundError): + """An exception derived from both pytz and zoneinfo + + This exception will be trappable both by pytz expecting clients and + zoneinfo expecting clients. + """ + + +def get_system_offset(): + """Get system's timezone offset using built-in library time. + + For the Timezone constants (altzone, daylight, timezone, and tzname), the + value is determined by the timezone rules in effect at module load time or + the last time tzset() is called and may be incorrect for times in the past. + + To keep compatibility with Windows, we're always importing time module here. + """ + + localtime = calendar.timegm(time.localtime()) + gmtime = calendar.timegm(time.gmtime()) + offset = gmtime - localtime + # We could get the localtime and gmtime on either side of a second switch + # so we check that the difference is less than one minute, because nobody + # has that small DST differences. + if abs(offset - time.altzone) < 60: + return -time.altzone # pragma: no cover + else: + return -time.timezone # pragma: no cover + + +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): + """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.""" + tz_offset = get_tz_offset(tz) + system_offset = get_system_offset() + if tz_offset != system_offset: + msg = ( + "Timezone offset does not match system offset: {} != {}. " + "Please, check your config files." + ).format(tz_offset, system_offset) + raise ValueError(msg) + + +def _tz_name_from_env(tzenv=None): + if tzenv is None: + tzenv = os.environ.get("TZ") + + if not tzenv: + return None + + if tzenv[0] == ":": + tzenv = tzenv[1:] + + if tzenv in windows_tz.tz_win: + # 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 windows_tz.tz_win: + # Yup, it is + return possible_tz + + # Maybe it's a short one, like UTC? + if parts[-1] in windows_tz.tz_win: + # Indeed + return parts[-1] + + +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: + zone = zoneinfo.ZoneInfo.from_file(tzfile, key=tzname) + return pds.wrap_zone(zone) + + # TZ must specify a zoneinfo zone. + try: + tz = pds.timezone(tzenv) + # That worked, so we return this: + return tz + except pds.UnknownTimeZoneError: + # Nope, it's something like "PST4DST" etc, we can't handle that. + raise ZoneInfoNotFoundError( + "tzlocal() does not support non-zoneinfo timezones like %s. \n" + "Please use a timezone in the form of Continent/City" % tzenv + ) from None |