1import importlib.util
2import sys
3from datetime import datetime
4
5import regex as re
6
7TIME_MATCHER = re.compile(
8 r".*?"
9 r"(?P<hour>2[0-3]|[0-1]\d|\d):"
10 r"(?P<minute>[0-5]\d|\d):"
11 r"(?P<second>6[0-1]|[0-5]\d|\d)"
12 r"\.(?P<microsecond>[0-9]{1,6})"
13)
14
15MS_SEARCHER = re.compile(r"\.(?P<microsecond>[0-9]{1,6})")
16
17
18def _exec_module(spec, module):
19 if hasattr(spec.loader, "exec_module"):
20 spec.loader.exec_module(module)
21 else:
22 # This can happen before Python 3.10
23 # if spec.loader is a zipimporter and the Python runtime is in a zipfile
24 code = spec.loader.get_code(module.__name__)
25 exec(code, module.__dict__)
26
27
28def patch_strptime():
29 """Monkey patching _strptime to avoid problems related with non-english
30 locale changes on the system.
31
32 For example, if system's locale is set to fr_FR. Parser won't recognize
33 any date since all languages are translated to english dates.
34 """
35 _strptime_spec = importlib.util.find_spec("_strptime")
36 _strptime = importlib.util.module_from_spec(_strptime_spec)
37 _exec_module(_strptime_spec, _strptime)
38 sys.modules["strptime_patched"] = _strptime
39
40 _calendar = importlib.util.module_from_spec(_strptime_spec)
41 _exec_module(_strptime_spec, _calendar)
42 sys.modules["calendar_patched"] = _calendar
43
44 _strptime._getlang = lambda: ("en_US", "UTF-8")
45 _strptime.calendar = _calendar
46 _strptime.calendar.day_abbr = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
47 _strptime.calendar.day_name = [
48 "monday",
49 "tuesday",
50 "wednesday",
51 "thursday",
52 "friday",
53 "saturday",
54 "sunday",
55 ]
56 _strptime.calendar.month_abbr = [
57 "",
58 "jan",
59 "feb",
60 "mar",
61 "apr",
62 "may",
63 "jun",
64 "jul",
65 "aug",
66 "sep",
67 "oct",
68 "nov",
69 "dec",
70 ]
71 _strptime.calendar.month_name = [
72 "",
73 "january",
74 "february",
75 "march",
76 "april",
77 "may",
78 "june",
79 "july",
80 "august",
81 "september",
82 "october",
83 "november",
84 "december",
85 ]
86
87 return _strptime._strptime_time
88
89
90__strptime = patch_strptime()
91
92
93def strptime(date_string, format):
94 obj = datetime(*__strptime(date_string, format)[:-3])
95
96 if "%f" in format:
97 try:
98 match_groups = TIME_MATCHER.match(date_string).groupdict()
99 ms = match_groups["microsecond"]
100 ms = ms + ((6 - len(ms)) * "0")
101 obj = obj.replace(microsecond=int(ms))
102 except AttributeError:
103 match_groups = MS_SEARCHER.search(date_string).groupdict()
104 ms = match_groups["microsecond"]
105 ms = ms + ((6 - len(ms)) * "0")
106 obj = obj.replace(microsecond=int(ms))
107
108 return obj