Various changes.
[python_utils.git] / tests / dateparse_utils_test.py
1 #!/usr/bin/env python3
2
3 import datetime
4 import random
5 import re
6 import unittest
7
8 import pytz
9
10 import dateparse.dateparse_utils as du
11 import unittest_utils as uu
12
13
14 parsable_expressions = [
15     ('today',
16      datetime.datetime(2021, 7, 2)),
17     ('tomorrow',
18      datetime.datetime(2021, 7, 3)),
19     ('yesterday',
20      datetime.datetime(2021, 7, 1)),
21     ('21:30',
22      datetime.datetime(2021, 7, 2, 21, 30, 0, 0)),
23     ('12:01am',
24      datetime.datetime(2021, 7, 2, 0, 1, 0, 0)),
25     ('12:02p',
26      datetime.datetime(2021, 7, 2, 12, 2, 0, 0)),
27     ('0:03',
28      datetime.datetime(2021, 7, 2, 0, 3, 0, 0)),
29     ('last wednesday',
30      datetime.datetime(2021, 6, 30)),
31     ('this wed',
32      datetime.datetime(2021, 7, 7)),
33     ('next wed',
34      datetime.datetime(2021, 7, 14)),
35     ('this coming tues',
36      datetime.datetime(2021, 7, 6)),
37     ('this past monday',
38      datetime.datetime(2021, 6, 28)),
39     ('4 days ago',
40      datetime.datetime(2021, 6, 28)),
41     ('4 mondays ago',
42      datetime.datetime(2021, 6, 7)),
43     ('4 months ago',
44      datetime.datetime(2021, 3, 2)),
45     ('3 days back',
46      datetime.datetime(2021, 6, 29)),
47     ('13 weeks from now',
48      datetime.datetime(2021, 10, 1)),
49     ('1 year from now',
50      datetime.datetime(2022, 7, 2)),
51     ('4 weeks from now',
52      datetime.datetime(2021, 7, 30)),
53     ('3 saturdays ago',
54      datetime.datetime(2021, 6, 12)),
55     ('4 months from today',
56      datetime.datetime(2021, 11, 2)),
57     ('4 years from yesterday',
58      datetime.datetime(2025, 7, 1)),
59     ('4 weeks from tomorrow',
60      datetime.datetime(2021, 7, 31)),
61     ('april 15, 2005',
62      datetime.datetime(2005, 4, 15)),
63     ('april 14',
64      datetime.datetime(2021, 4, 14)),
65     ('9:30am on last wednesday',
66      datetime.datetime(2021, 6, 30, 9, 30)),
67     ('2005/apr/15',
68      datetime.datetime(2005, 4, 15)),
69     ('2005 apr 15',
70      datetime.datetime(2005, 4, 15)),
71     ('the 1st wednesday in may',
72      datetime.datetime(2021, 5, 5)),
73     ('last sun of june',
74      datetime.datetime(2021, 6, 27)),
75     ('this Easter',
76      datetime.datetime(2021, 4, 4)),
77     ('last christmas',
78      datetime.datetime(2020, 12, 25)),
79     ('last Xmas',
80      datetime.datetime(2020, 12, 25)),
81     ('xmas, 1999',
82      datetime.datetime(1999, 12, 25)),
83     ('next mlk day',
84      datetime.datetime(2022, 1, 17)),
85     ('Halloween, 2020',
86      datetime.datetime(2020, 10, 31)),
87     ('5 work days after independence day',
88      datetime.datetime(2021, 7, 12)),
89     ('50 working days from last wed',
90      datetime.datetime(2021, 9, 10)),
91     ('25 working days before columbus day',
92      datetime.datetime(2021, 9, 3)),
93     ('today +1 week',
94      datetime.datetime(2021, 7, 9)),
95     ('sunday -3 weeks',
96      datetime.datetime(2021, 6, 13)),
97     ('4 weeks before xmas, 1999',
98      datetime.datetime(1999, 11, 27)),
99     ('3 days before new years eve, 2000',
100      datetime.datetime(2000, 12, 28)),
101     ('july 4th',
102      datetime.datetime(2021, 7, 4)),
103     ('the ides of march',
104      datetime.datetime(2021, 3, 15)),
105     ('the nones of april',
106      datetime.datetime(2021, 4, 5)),
107     ('the kalends of may',
108      datetime.datetime(2021, 5, 1)),
109     ('9/11/2001',
110      datetime.datetime(2001, 9, 11)),
111     ('4 sundays before veterans\' day',
112      datetime.datetime(2021, 10, 17)),
113     ('xmas eve',
114      datetime.datetime(2021, 12, 24)),
115     ('this friday at 5pm',
116      datetime.datetime(2021, 7, 9, 17, 0, 0)),
117     ('presidents day',
118      datetime.datetime(2021, 2, 15)),
119     ('memorial day, 1921',
120      datetime.datetime(1921, 5, 30)),
121     ('today -4 wednesdays',
122      datetime.datetime(2021, 6, 9)),
123     ('thanksgiving',
124      datetime.datetime(2021, 11, 25)),
125     ('2 sun in jun',
126      datetime.datetime(2021, 6, 13)),
127     ('easter -40 days',
128      datetime.datetime(2021, 2, 23)),
129     ('easter +39 days',
130      datetime.datetime(2021, 5, 13)),
131     ('1st tuesday in nov, 2024',
132      datetime.datetime(2024, 11, 5)),
133     ('2 days before last xmas at 3:14:15.92a',
134      datetime.datetime(2020, 12, 23, 3, 14, 15, 92)),
135     ('3 weeks after xmas, 1995 at midday',
136      datetime.datetime(1996, 1, 15, 12, 0, 0)),
137     ('4 months before easter, 1992 at midnight',
138      datetime.datetime(1991, 12, 19)),
139     ('5 months before halloween, 1995 at noon',
140      datetime.datetime(1995, 5, 31, 12)),
141     ('4 days before last wednesday',
142      datetime.datetime(2021, 6, 26)),
143     ('44 months after today',
144      datetime.datetime(2025, 3, 2)),
145     ('44 years before today',
146      datetime.datetime(1977, 7, 2)),
147     ('44 weeks ago',
148      datetime.datetime(2020, 8, 28)),
149     ('15 minutes to 3am',
150      datetime.datetime(2021, 7, 2, 2, 45)),
151     ('quarter past 4pm',
152      datetime.datetime(2021, 7, 2, 16, 15)),
153     ('half past 9',
154      datetime.datetime(2021, 7, 2, 9, 30)),
155     ('4 seconds to midnight',
156      datetime.datetime(2021, 7, 1, 23, 59, 56)),
157     ('4 seconds to midnight, tomorrow',
158      datetime.datetime(2021, 7, 2, 23, 59, 56)),
159     ('2021/apr/15T21:30:44.55',
160      datetime.datetime(2021, 4, 15, 21, 30, 44, 55)),
161     ('2021/apr/15 at 21:30:44.55',
162      datetime.datetime(2021, 4, 15, 21, 30, 44, 55)),
163     ('2021/4/15 at 21:30:44.55',
164      datetime.datetime(2021, 4, 15, 21, 30, 44, 55)),
165     ('2021/04/15 at 21:30:44.55',
166      datetime.datetime(2021, 4, 15, 21, 30, 44, 55)),
167     ('2021/04/15 at 21:30:44.55Z',
168      datetime.datetime(2021, 4, 15, 21, 30, 44, 55,
169                        tzinfo=pytz.timezone('UTC'))),
170     ('2021/04/15 at 21:30:44.55EST',
171      datetime.datetime(2021, 4, 15, 21, 30, 44, 55,
172                        tzinfo=pytz.timezone('EST'))),
173     ('13 days after last memorial day at 12 seconds before 4pm',
174      datetime.datetime(2020, 6, 7, 15, 59, 48)),
175     ('    2     days     before   yesterday    at   9am      ',
176      datetime.datetime(2021, 6, 29, 9)),
177     ('-3 days before today',
178      datetime.datetime(2021, 7, 5)),
179     ('3 days before yesterday at midnight EST',
180      datetime.datetime(2021, 6, 28, tzinfo=pytz.timezone('EST')))
181 ]
182
183
184 class TestDateparseUtils(unittest.TestCase):
185
186     @uu.check_method_for_perf_regressions
187     def test_dateparsing(self):
188         dp = du.DateParser(
189             override_now_for_test_purposes = datetime.datetime(2021, 7, 2)
190         )
191
192         for (txt, expected_dt) in parsable_expressions:
193             try:
194                 actual_dt = dp.parse(txt)
195                 self.assertIsNotNone(actual_dt)
196                 self.assertEqual(
197                     actual_dt,
198                     expected_dt,
199                     f'"{txt}", got "{actual_dt}" while expecting "{expected_dt}"'
200                 )
201             except du.ParseException:
202                 self.fail(f'Expected "{txt}" to parse successfully.')
203
204     def test_whitespace_handling(self):
205         dp = du.DateParser(
206             override_now_for_test_purposes = datetime.datetime(2021, 7, 2)
207         )
208
209         for (txt, expected_dt) in parsable_expressions:
210             try:
211                 txt = f' {txt} '
212                 i = random.randint(2, 5)
213                 replacement = ' ' * i
214                 txt = re.sub('\s', replacement, txt)
215                 actual_dt = dp.parse(txt)
216                 self.assertIsNotNone(actual_dt)
217                 self.assertEqual(
218                     actual_dt,
219                     expected_dt,
220                     f'"{txt}", got "{actual_dt}" while expecting "{expected_dt}"'
221                 )
222             except du.ParseException:
223                 self.fail(f'Expected "{txt}" to parse successfully.')
224
225
226 if __name__ == '__main__':
227     unittest.main()