1Exercises 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 13 14.. _mlk-day-exercise: 15 16Martin Luther King Day 17-------------------------------- 18 19 20 `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? 21 22 How would you generate a `recurrence rule <../rrule.html>`_ that generates Martin Luther King Day, starting from its first observance in 1986? 23 24 25**Test Script** 26 27To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks. 28 29.. raw:: html 30 31 <details> 32 33.. code-block:: python3 34 35 # ------- YOUR CODE -------------# 36 from dateutil import rrule 37 38 MLK_DAY = <<YOUR CODE HERE>> 39 40 # -------------------------------# 41 42 from datetime import datetime 43 MLK_TEST_CASES = [ 44 ((datetime(1970, 1, 1), datetime(1980, 1, 1)), 45 []), 46 ((datetime(1980, 1, 1), datetime(1989, 1, 1)), 47 [datetime(1986, 1, 20), 48 datetime(1987, 1, 19), 49 datetime(1988, 1, 18)]), 50 ((datetime(2017, 2, 1), datetime(2022, 2, 1)), 51 [datetime(2018, 1, 15, 0, 0), 52 datetime(2019, 1, 21, 0, 0), 53 datetime(2020, 1, 20, 0, 0), 54 datetime(2021, 1, 18, 0, 0), 55 datetime(2022, 1, 17, 0, 0)] 56 ), 57 ] 58 59 def test_mlk_day(): 60 for (between_args, expected) in MLK_TEST_CASES: 61 assert MLK_DAY.between(*between_args) == expected 62 63 if __name__ == "__main__": 64 test_mlk_day() 65 print('Success!') 66 67.. raw:: html 68 69 </details> 70 71A solution to this problem is provided :doc:`here <solutions/mlk-day-rrule>`. 72 73 74Next Monday meeting 75------------------- 76 77 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>`_. 78 79**Test Script** 80 81To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks. 82 83.. raw:: html 84 85 <details> 86 87 88.. code-block:: python3 89 90 # --------- YOUR CODE -------------- # 91 from dateutil import relativedelta 92 93 def next_monday(dt): 94 <<YOUR CODE HERE>> 95 96 # ---------------------------------- # 97 98 from datetime import datetime 99 from dateutil import tz 100 101 NEXT_MONDAY_CASES = [ 102 (datetime(2018, 4, 11, 14, 30, 15, 123456), 103 datetime(2018, 4, 16, 10, 0)), 104 (datetime(2018, 4, 16, 10, 0), 105 datetime(2018, 4, 16, 10, 0)), 106 (datetime(2018, 4, 16, 10, 30), 107 datetime(2018, 4, 23, 10, 0)), 108 (datetime(2018, 4, 14, 9, 30, tzinfo=tz.gettz('America/New_York')), 109 datetime(2018, 4, 16, 10, 0, tzinfo=tz.gettz('America/New_York'))), 110 ] 111 112 def test_next_monday_1(): 113 for dt_in, dt_out in NEXT_MONDAY_CASES: 114 assert next_monday(dt_in) == dt_out 115 116 if __name__ == "__main__": 117 test_next_monday_1() 118 print('Success!') 119 120.. raw:: html 121 122 </details> 123 124 125Parsing a local tzname 126---------------------- 127 128 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. 129 130Problem 1 131********* 132 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. 133 134 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. 135 136**Test Script** 137 138To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks. 139 140.. raw:: html 141 142 <details> 143 144 145.. code-block:: python3 146 147 # --------- YOUR CODE -------------- # 148 from dateutil.parser import parse 149 from dateutil import tz 150 151 def parse_func_us_jp_ind(): 152 <<YOUR CODE HERE>> 153 154 # ---------------------------------- # 155 156 from dateutil import tz 157 from datetime import datetime 158 159 160 PARSE_TZ_TEST_DATETIMES = [ 161 datetime(2018, 1, 1, 12, 0), 162 datetime(2018, 3, 20, 2, 0), 163 datetime(2018, 5, 12, 3, 30), 164 datetime(2014, 9, 1, 23) 165 ] 166 167 PARSE_TZ_TEST_ZONES = [ 168 tz.gettz('America/New_York'), 169 tz.gettz('America/Chicago'), 170 tz.gettz('America/Denver'), 171 tz.gettz('America/Los_Angeles'), 172 tz.gettz('Asia/Kolkata'), 173 tz.gettz('Asia/Tokyo'), 174 ] 175 176 def test_parse(): 177 for tzi in PARSE_TZ_TEST_ZONES: 178 for dt in PARSE_TZ_TEST_DATETIMES: 179 dt_exp = dt.replace(tzinfo=tzi) 180 dtstr = dt_exp.strftime('%Y-%m-%d %H:%M:%S %Z') 181 182 dt_act = parse_func_us_jp_ind(dtstr) 183 assert dt_act == dt_exp 184 assert dt_act.tzinfo is dt_exp.tzinfo 185 186 if __name__ == "__main__": 187 test_parse() 188 print('Success!') 189 190.. raw:: html 191 192 </details> 193 194 195Problem 2 196********* 197 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. 198 199**Test Script** 200 201To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks. 202 203 204.. raw:: html 205 206 <details> 207 208.. code-block:: python3 209 210 # --------- YOUR CODE -------------- # 211 from dateutil.parser import parse 212 from dateutil import tz 213 214 def parse_func_ind_ire(): 215 <<YOUR CODE HERE>> 216 217 # ---------------------------------- # 218 ISRAEL = tz.gettz('Asia/Jerusalem') 219 INDIA = tz.gettz('Asia/Kolkata') 220 PARSE_IXT_TEST_CASE = [ 221 ('2018-02-03 12:00 IST+02:00', datetime(2018, 2, 3, 12, tzinfo=ISRAEL)), 222 ('2018-06-14 12:00 IDT+03:00', datetime(2018, 6, 14, 12, tzinfo=ISRAEL)), 223 ('2018-06-14 12:00 IST', datetime(2018, 6, 14, 12, tzinfo=INDIA)), 224 ('2018-06-14 12:00 IST+05:30', datetime(2018, 6, 14, 12, tzinfo=INDIA)), 225 ('2018-02-03 12:00 IST', datetime(2018, 2, 3, 12, tzinfo=INDIA)), 226 ] 227 228 229 def test_parse_ixt(): 230 for dtstr, dt_exp in PARSE_IXT_TEST_CASE: 231 dt_act = parse_func_ind_ire(dtstr) 232 assert dt_act == dt_exp, (dt_act, dt_exp) 233 assert dt_act.tzinfo is dt_exp.tzinfo, (dt_act, dt_exp) 234 235 if __name__ == "__main__": 236 test_parse_ixt() 237 print('Success!') 238 239.. raw:: html 240 241 </details> 242 243