Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tzlocal/utils.py: 46%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import calendar
2import datetime
3import logging
4import os
5import time
6import warnings
8try:
9 import zoneinfo # pragma: no cover
10except ImportError:
11 from backports import zoneinfo # pragma: no cover
13from tzlocal import windows_tz
15log = logging.getLogger("tzlocal")
18def get_tz_offset(tz):
19 """Get timezone's offset using built-in function datetime.utcoffset()."""
20 return int(datetime.datetime.now(tz).utcoffset().total_seconds())
23def assert_tz_offset(tz, error=True):
24 """Assert that system's timezone offset equals to the timezone offset found.
26 If they don't match, we probably have a misconfiguration, for example, an
27 incorrect timezone set in /etc/timezone file in systemd distributions.
29 If error is True, this method will raise a ValueError, otherwise it will
30 emit a warning.
31 """
33 tz_offset = get_tz_offset(tz)
34 system_offset = calendar.timegm(time.localtime()) - calendar.timegm(time.gmtime())
35 # No one has timezone offsets less than a minute, so this should be close enough:
36 if abs(tz_offset - system_offset) > 60:
37 msg = (
38 f"Timezone offset does not match system offset: {tz_offset} != {system_offset}. "
39 "Please, check your config files."
40 )
41 if error:
42 raise ValueError(msg)
43 warnings.warn(msg)
46def _tz_name_from_env(tzenv=None):
47 if tzenv is None:
48 tzenv = os.environ.get("TZ")
50 if not tzenv:
51 return None
53 log.debug(f"Found a TZ environment: {tzenv}")
55 if tzenv[0] == ":":
56 tzenv = tzenv[1:]
58 if tzenv in windows_tz.tz_win:
59 # Yup, it's a timezone
60 return tzenv
62 if os.path.isabs(tzenv) and os.path.exists(tzenv):
63 # It's a file specification, expand it, if possible
64 parts = os.path.realpath(tzenv).split(os.sep)
66 # Is it a zone info zone?
67 possible_tz = "/".join(parts[-2:])
68 if possible_tz in windows_tz.tz_win:
69 # Yup, it is
70 return possible_tz
72 # Maybe it's a short one, like UTC?
73 if parts[-1] in windows_tz.tz_win:
74 # Indeed
75 return parts[-1]
77 log.debug("TZ does not contain a time zone name")
78 return None
81def _tz_from_env(tzenv=None):
82 if tzenv is None:
83 tzenv = os.environ.get("TZ")
85 if not tzenv:
86 return None
88 # Some weird format that exists:
89 if tzenv[0] == ":":
90 tzenv = tzenv[1:]
92 # TZ specifies a file
93 if os.path.isabs(tzenv) and os.path.exists(tzenv):
94 # Try to see if we can figure out the name
95 tzname = _tz_name_from_env(tzenv)
96 if not tzname:
97 # Nope, not a standard timezone name, just take the filename
98 tzname = tzenv.split(os.sep)[-1]
99 with open(tzenv, "rb") as tzfile:
100 return zoneinfo.ZoneInfo.from_file(tzfile, key=tzname)
102 # TZ must specify a zoneinfo zone.
103 try:
104 tz = zoneinfo.ZoneInfo(tzenv)
105 # That worked, so we return this:
106 return tz
107 except zoneinfo.ZoneInfoNotFoundError:
108 # Nope, it's something like "PST4DST" etc, we can't handle that.
109 raise zoneinfo.ZoneInfoNotFoundError(
110 f"tzlocal() does not support non-zoneinfo timezones like {tzenv}. \n"
111 "Please use a timezone in the form of Continent/City"
112 ) from None