Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/tzlocal/utils.py: 45%

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

56 statements  

1import calendar 

2import datetime 

3import logging 

4import os 

5import time 

6import warnings 

7import zoneinfo 

8 

9from tzlocal import windows_tz 

10 

11log = logging.getLogger("tzlocal") 

12 

13 

14def get_tz_offset(tz): 

15 """Get timezone's offset using built-in function datetime.utcoffset().""" 

16 return int(datetime.datetime.now(tz).utcoffset().total_seconds()) 

17 

18 

19def assert_tz_offset(tz, error=True): 

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

21 

22 If they don't match, we probably have a misconfiguration, for example, an 

23 incorrect timezone set in /etc/timezone file in systemd distributions. 

24 

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

26 emit a warning. 

27 """ 

28 

29 tz_offset = get_tz_offset(tz) 

30 system_offset = calendar.timegm(time.localtime()) - calendar.timegm(time.gmtime()) 

31 # No one has timezone offsets less than a minute, so this should be close enough: 

32 if abs(tz_offset - system_offset) > 60: 

33 msg = ( 

34 f"Timezone offset does not match system offset: {tz_offset} != {system_offset}. " 

35 "Please, check your config files." 

36 ) 

37 if error: 

38 raise ValueError(msg) 

39 warnings.warn(msg) 

40 

41 

42def _tz_name_from_env(tzenv=None): 

43 if tzenv is None: 

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

45 

46 if not tzenv: 

47 return None 

48 

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

50 

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

52 tzenv = tzenv[1:] 

53 

54 if tzenv in windows_tz.tz_win: 

55 # Yup, it's a timezone 

56 return tzenv 

57 

58 if os.path.isabs(tzenv) and os.path.exists(tzenv): 

59 # It's a file specification, expand it, if possible 

60 parts = os.path.realpath(tzenv).split(os.sep) 

61 

62 # Is it a zone info zone? 

63 possible_tz = "/".join(parts[-2:]) 

64 if possible_tz in windows_tz.tz_win: 

65 # Yup, it is 

66 return possible_tz 

67 

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

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

70 # Indeed 

71 return parts[-1] 

72 

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

74 return None 

75 

76 

77def _tz_from_env(tzenv=None): 

78 if tzenv is None: 

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

80 

81 if not tzenv: 

82 return None 

83 

84 # Some weird format that exists: 

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

86 tzenv = tzenv[1:] 

87 

88 # TZ specifies a file 

89 if os.path.isabs(tzenv) and os.path.exists(tzenv): 

90 # Try to see if we can figure out the name 

91 tzname = _tz_name_from_env(tzenv) 

92 if not tzname: 

93 # Nope, not a standard timezone name, just take the filename 

94 tzname = tzenv.split(os.sep)[-1] 

95 with open(tzenv, "rb") as tzfile: 

96 return zoneinfo.ZoneInfo.from_file(tzfile, key=tzname) 

97 

98 # TZ must specify a zoneinfo zone. 

99 try: 

100 tz = zoneinfo.ZoneInfo(tzenv) 

101 # That worked, so we return this: 

102 return tz 

103 except zoneinfo.ZoneInfoNotFoundError: 

104 # Nope, it's something like "PST4DST" etc, we can't handle that. 

105 raise zoneinfo.ZoneInfoNotFoundError( 

106 f"tzlocal() does not support non-zoneinfo timezones like {tzenv}. \n" 

107 "Please use a timezone in the form of Continent/City" 

108 ) from None