Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/dateparser/timezone_parser.py: 68%

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

77 statements  

1import os 

2import pickle 

3import zlib 

4from datetime import datetime, timedelta, timezone, tzinfo 

5from pathlib import Path 

6 

7import regex as re 

8 

9from .timezones import timezone_info_list 

10 

11 

12class StaticTzInfo(tzinfo): 

13 def __init__(self, name, offset): 

14 self.__offset = offset 

15 self.__name = name 

16 

17 def tzname(self, dt): 

18 return self.__name 

19 

20 def utcoffset(self, dt): 

21 return self.__offset 

22 

23 def dst(self, dt): 

24 return timedelta(0) 

25 

26 def __repr__(self): 

27 return "<%s '%s'>" % (self.__class__.__name__, self.__name) 

28 

29 def localize(self, dt, is_dst=False): 

30 if dt.tzinfo is not None: 

31 raise ValueError("Not naive datetime (tzinfo is already set)") 

32 return dt.replace(tzinfo=self) 

33 

34 def __getinitargs__(self): 

35 return self.__name, self.__offset 

36 

37 

38def pop_tz_offset_from_string(date_string, as_offset=True): 

39 if _search_regex_ignorecase.search(date_string): 

40 for name, info in _tz_offsets: 

41 timezone_re = info["regex"] 

42 timezone_match = timezone_re.search(date_string) 

43 if timezone_match: 

44 start, stop = timezone_match.span() 

45 date_string = date_string[: start + 1] + date_string[stop:] 

46 return ( 

47 date_string, 

48 StaticTzInfo(name, info["offset"]) if as_offset else name, 

49 ) 

50 return date_string, None 

51 

52 

53def word_is_tz(word): 

54 return bool(_search_regex.match(word)) 

55 

56 

57def convert_to_local_tz(datetime_obj, datetime_tz_offset): 

58 return datetime_obj - datetime_tz_offset + local_tz_offset 

59 

60 

61def build_tz_offsets(search_regex_parts): 

62 def get_offset(tz_obj, regex, repl="", replw=""): 

63 return ( 

64 tz_obj[0], 

65 { 

66 "regex": re.compile( 

67 re.sub(repl, replw, regex % tz_obj[0]), re.IGNORECASE 

68 ), 

69 "offset": timedelta(seconds=tz_obj[1]), 

70 }, 

71 ) 

72 

73 for tz_info in timezone_info_list: 

74 for regex in tz_info["regex_patterns"]: 

75 for tz_obj in tz_info["timezones"]: 

76 search_regex_parts.append(tz_obj[0]) 

77 yield get_offset(tz_obj, regex) 

78 

79 # alternate patterns 

80 for replace, replacewith in tz_info.get("replace", []): 

81 search_regex_parts.append(re.sub(replace, replacewith, tz_obj[0])) 

82 yield get_offset(tz_obj, regex, repl=replace, replw=replacewith) 

83 

84 

85def get_local_tz_offset(): 

86 offset = datetime.now() - datetime.now(tz=timezone.utc).replace(tzinfo=None) 

87 offset = timedelta(days=offset.days, seconds=round(offset.seconds, -1)) 

88 return offset 

89 

90 

91local_tz_offset = get_local_tz_offset() 

92 

93_tz_offsets = None 

94_search_regex = None 

95_search_regex_ignorecase = None 

96 

97 

98def _load_offsets(cache_path, current_hash): 

99 global _tz_offsets, _search_regex, _search_regex_ignorecase 

100 

101 try: 

102 with open(cache_path, mode="rb") as file: 

103 ( 

104 serialized_hash, 

105 _tz_offsets, 

106 _search_regex, 

107 _search_regex_ignorecase, 

108 ) = pickle.load(file) 

109 if current_hash is None or current_hash == serialized_hash: 

110 return 

111 except (FileNotFoundError, ValueError, TypeError): 

112 pass 

113 

114 _search_regex_parts = [] 

115 _tz_offsets = list(build_tz_offsets(_search_regex_parts)) 

116 _search_regex = re.compile("|".join(_search_regex_parts)) 

117 _search_regex_ignorecase = re.compile("|".join(_search_regex_parts), re.IGNORECASE) 

118 

119 with open(cache_path, mode="wb") as file: 

120 pickle.dump( 

121 (current_hash, _tz_offsets, _search_regex, _search_regex_ignorecase), 

122 file, 

123 protocol=5, 

124 ) 

125 

126 

127CACHE_PATH = Path(__file__).parent.joinpath("data", "dateparser_tz_cache.pkl") 

128 

129if "BUILD_TZ_CACHE" in os.environ: 

130 current_hash = zlib.crc32(str(timezone_info_list).encode("utf-8")) 

131else: 

132 current_hash = None 

133 

134_load_offsets(CACHE_PATH, current_hash)