blob: 85c7e0b9121f66e3e41e9c9f777e78fba62c2713 [file] [log] [blame]
Paul Ganssle4c0ba122018-06-07 20:07:21 +01001Exercises
2=========
3
4It is often useful to work through some examples in order to understand how a module works; on this page, there are several exercises of varying difficulty that you can use to learn how to use ``dateutil``.
5
6If you are interested in helping improve the documentation of ``dateutil``, it is recommended that you attempt to complete these exercises with no resources *other than dateutil's documentation*. If you find that the documentation is not clear enough to allow you to complete these exercises, open an issue on the `dateutil issue tracker <https://github.com/dateutil/dateutil/issues>`_ to let the developers know what part of the documentation needs improvement.
7
8
9.. contents:: Table of Contents
10 :backlinks: top
11 :local:
12
Paul Ganssle404af912018-06-07 20:09:47 +010013
14Martin Luther King Day
15--------------------------------
16
17
18 `Martin Luther King, Jr Day <https://en.wikipedia.org/wiki/Martin_Luther_King_Jr._Day>`_ is a US holiday that occurs every year on the third Monday in January?
19
20 How would you generate a `recurrence rule <../rrule.html>`_ that generates Martin Luther King Day, starting from its first observance in 1986?
21
22
23**Test Script**
24
25To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks.
26
27.. raw:: html
28
29 <details>
30
31.. code-block:: python3
32
33 # ------- YOUR CODE -------------#
34 from dateutil import rrule
35
36 MLK_DAY = <<YOUR CODE HERE>>
37
38 # -------------------------------#
39
40 from datetime import datetime
41 MLK_TEST_CASES = [
42 ((datetime(1970, 1, 1), datetime(1980, 1, 1)),
43 []),
44 ((datetime(1980, 1, 1), datetime(1989, 1, 1)),
45 [datetime(1986, 1, 20),
46 datetime(1987, 1, 19),
47 datetime(1988, 1, 18)]),
48 ((datetime(2017, 2, 1), datetime(2022, 2, 1)),
49 [datetime(2018, 1, 15, 0, 0),
50 datetime(2019, 1, 21, 0, 0),
51 datetime(2020, 1, 20, 0, 0),
52 datetime(2021, 1, 18, 0, 0),
53 datetime(2022, 1, 17, 0, 0)]
54 ),
55 ]
56
57 def test_mlk_day():
58 for (between_args, expected) in MLK_TEST_CASES:
59 assert MLK_DAY.between(*between_args) == expected
60
61 if __name__ == "__main__":
62 test_mlk_day()
63 print('Success!')
64
Paul Gansslea5c248b2018-06-08 07:26:25 +010065.. raw:: html
66
67 </details>
68
69
70
71Next Monday meeting
72-------------------
73
74 A team has a meeting at 10 AM every Monday and wants a function that tells them, given a ``datetime.datetime`` object, what is the date and time of the *next* Monday meeting? This is probably best accomplished using a `relativedelta <../relativedelta.html>`_.
75
76**Test Script**
77
78To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks.
79
80.. raw:: html
81
82 <details>
83
84
85.. code-block:: python3
86
87 # --------- YOUR CODE -------------- #
88 from dateutil import relativedelta
89
90 def next_monday(dt):
91 <<YOUR CODE HERE>>
92
93 # ---------------------------------- #
94
95 from datetime import datetime
96 from dateutil import tz
97
98 NEXT_MONDAY_CASES = [
99 (datetime(2018, 4, 11, 14, 30, 15, 123456),
100 datetime(2018, 4, 16, 10, 0)),
101 (datetime(2018, 4, 16, 10, 0),
102 datetime(2018, 4, 16, 10, 0)),
103 (datetime(2018, 4, 16, 10, 30),
104 datetime(2018, 4, 23, 10, 0)),
105 (datetime(2018, 4, 14, 9, 30, tzinfo=tz.gettz('America/New_York')),
106 datetime(2018, 4, 16, 10, 0, tzinfo=tz.gettz('America/New_York'))),
107 ]
108
109 def test_next_monday_1():
110 for dt_in, dt_out in NEXT_MONDAY_CASES:
111 assert next_monday(dt_in) == dt_out
112
113 if __name__ == "__main__":
114 test_next_monday_1()
Paul Ganssle94350082018-06-08 07:14:30 +0100115 print('Success!')
Paul Ganssle404af912018-06-07 20:09:47 +0100116
117.. raw:: html
118
119 </details>
120
121
Paul Ganssle94350082018-06-08 07:14:30 +0100122Parsing a local tzname
123----------------------
124
daplantagenet121d5e02018-06-08 11:02:41 +0100125 Three-character time zone abbreviations are *not* unique in that they do not explicitly map to a time zone. A list of time zone abbreviations in use can be found `here <https://www.timeanddate.com/time/zones/>`_. This means that parsing a datetime string such as ``'2018-01-01 12:30:30 CST'`` is ambiguous without context. Using `dateutil.parser <../parser.html>`_ and `dateutil.tz <../tz.html>`_, it is possible to provide a context such that these local names are converted to proper time zones.
Paul Ganssle94350082018-06-08 07:14:30 +0100126
127Problem 1
128*********
129 Given the context that you will only be parsing dates coming from the continental United States, India and Japan, write a function that parses a datetime string and returns a timezone-aware ``datetime`` with an IANA-style timezone attached.
130
131 Note: For the purposes of the experiment, you may ignore the portions of the United States like Arizona and parts of Indiana that do not observe daylight saving time.
132
133**Test Script**
134
135To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks.
136
137.. raw:: html
138
139 <details>
140
141
142.. code-block:: python3
143
144 # --------- YOUR CODE -------------- #
145 from dateutil.parser import parse
146 from dateutil import tz
147
148 def parse_func_us_jp_ind():
149 <<YOUR CODE HERE>>
150
151 # ---------------------------------- #
152
153 from dateutil import tz
154 from datetime import datetime
155
156
157 PARSE_TZ_TEST_DATETIMES = [
158 datetime(2018, 1, 1, 12, 0),
159 datetime(2018, 3, 20, 2, 0),
160 datetime(2018, 5, 12, 3, 30),
161 datetime(2014, 9, 1, 23)
162 ]
163
164 PARSE_TZ_TEST_ZONES = [
165 tz.gettz('America/New_York'),
166 tz.gettz('America/Chicago'),
167 tz.gettz('America/Denver'),
168 tz.gettz('America/Los_Angeles'),
169 tz.gettz('Asia/Kolkata'),
170 tz.gettz('Asia/Tokyo'),
171 ]
172
173 def test_parse():
174 for tzi in PARSE_TZ_TEST_ZONES:
175 for dt in PARSE_TZ_TEST_DATETIMES:
176 dt_exp = dt.replace(tzinfo=tzi)
177 dtstr = dt_exp.strftime('%Y-%m-%d %H:%M:%S %Z')
178
179 dt_act = parse_func_us_jp_ind(dtstr)
180 assert dt_act == dt_exp
181 assert dt_act.tzinfo is dt_exp.tzinfo
182
183 if __name__ == "__main__":
184 test_parse()
185 print('Success!')
186
187.. raw:: html
188
189 </details>
190
191
192Problem 2
193*********
194 Given the context that you will *only* be passed dates from India or Ireland, write a function that correctly parses all *unambiguous* time zone strings to aware datetimes localized to the correct IANA zone, and for *ambiguous* time zone strings default to India.
195
196**Test Script**
197
198To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks.
199
200
201.. raw:: html
202
203 <details>
204
205.. code-block:: python3
206
207 # --------- YOUR CODE -------------- #
208 from dateutil.parser import parse
209 from dateutil import tz
210
211 def parse_func_ind_ire():
212 <<YOUR CODE HERE>>
213
214 # ---------------------------------- #
215 ISRAEL = tz.gettz('Asia/Jerusalem')
216 INDIA = tz.gettz('Asia/Kolkata')
217 PARSE_IXT_TEST_CASE = [
218 ('2018-02-03 12:00 IST+02:00', datetime(2018, 2, 3, 12, tzinfo=ISRAEL)),
219 ('2018-06-14 12:00 IDT+03:00', datetime(2018, 6, 14, 12, tzinfo=ISRAEL)),
220 ('2018-06-14 12:00 IST', datetime(2018, 6, 14, 12, tzinfo=INDIA)),
221 ('2018-06-14 12:00 IST+05:30', datetime(2018, 6, 14, 12, tzinfo=INDIA)),
222 ('2018-02-03 12:00 IST', datetime(2018, 2, 3, 12, tzinfo=INDIA)),
223 ]
224
225
226 def test_parse_ixt():
227 for dtstr, dt_exp in PARSE_IXT_TEST_CASE:
228 dt_act = parse_func_ind_ire(dtstr)
229 assert dt_act == dt_exp, (dt_act, dt_exp)
230 assert dt_act.tzinfo is dt_exp.tzinfo, (dt_act, dt_exp)
231
232 if __name__ == "__main__":
233 test_parse_ixt()
234 print('Success!')
235
236.. raw:: html
237
238 </details>
239