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