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

57 statements  

1import calendar 

2import datetime 

3import logging 

4import os 

5import time 

6import warnings 

7 

8try: 

9 import zoneinfo # pragma: no cover 

10except ImportError: 

11 from backports import zoneinfo # pragma: no cover 

12 

13from tzlocal import windows_tz 

14 

15log = logging.getLogger("tzlocal") 

16 

17 

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()) 

21 

22 

23def assert_tz_offset(tz, error=True): 

24 """Assert that system's timezone offset equals to the timezone offset found. 

25 

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. 

28 

29 If error is True, this method will raise a ValueError, otherwise it will 

30 emit a warning. 

31 """ 

32 

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) 

44 

45 

46def _tz_name_from_env(tzenv=None): 

47 if tzenv is None: 

48 tzenv = os.environ.get("TZ") 

49 

50 if not tzenv: 

51 return None 

52 

53 log.debug(f"Found a TZ environment: {tzenv}") 

54 

55 if tzenv[0] == ":": 

56 tzenv = tzenv[1:] 

57 

58 if tzenv in windows_tz.tz_win: 

59 # Yup, it's a timezone 

60 return tzenv 

61 

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) 

65 

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 

71 

72 # Maybe it's a short one, like UTC? 

73 if parts[-1] in windows_tz.tz_win: 

74 # Indeed 

75 return parts[-1] 

76 

77 log.debug("TZ does not contain a time zone name") 

78 return None 

79 

80 

81def _tz_from_env(tzenv=None): 

82 if tzenv is None: 

83 tzenv = os.environ.get("TZ") 

84 

85 if not tzenv: 

86 return None 

87 

88 # Some weird format that exists: 

89 if tzenv[0] == ":": 

90 tzenv = tzenv[1:] 

91 

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) 

101 

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