You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
7.6 KiB
243 lines
7.6 KiB
Exercises
|
|
=========
|
|
|
|
It 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``.
|
|
|
|
If 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.
|
|
|
|
|
|
.. contents:: Table of Contents
|
|
:backlinks: top
|
|
:local:
|
|
|
|
|
|
.. _mlk-day-exercise:
|
|
|
|
Martin Luther King Day
|
|
--------------------------------
|
|
|
|
|
|
`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?
|
|
|
|
How would you generate a `recurrence rule <../rrule.html>`_ that generates Martin Luther King Day, starting from its first observance in 1986?
|
|
|
|
|
|
**Test Script**
|
|
|
|
To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks.
|
|
|
|
.. raw:: html
|
|
|
|
<details>
|
|
|
|
.. code-block:: python3
|
|
|
|
# ------- YOUR CODE -------------#
|
|
from dateutil import rrule
|
|
|
|
MLK_DAY = <<YOUR CODE HERE>>
|
|
|
|
# -------------------------------#
|
|
|
|
from datetime import datetime
|
|
MLK_TEST_CASES = [
|
|
((datetime(1970, 1, 1), datetime(1980, 1, 1)),
|
|
[]),
|
|
((datetime(1980, 1, 1), datetime(1989, 1, 1)),
|
|
[datetime(1986, 1, 20),
|
|
datetime(1987, 1, 19),
|
|
datetime(1988, 1, 18)]),
|
|
((datetime(2017, 2, 1), datetime(2022, 2, 1)),
|
|
[datetime(2018, 1, 15, 0, 0),
|
|
datetime(2019, 1, 21, 0, 0),
|
|
datetime(2020, 1, 20, 0, 0),
|
|
datetime(2021, 1, 18, 0, 0),
|
|
datetime(2022, 1, 17, 0, 0)]
|
|
),
|
|
]
|
|
|
|
def test_mlk_day():
|
|
for (between_args, expected) in MLK_TEST_CASES:
|
|
assert MLK_DAY.between(*between_args) == expected
|
|
|
|
if __name__ == "__main__":
|
|
test_mlk_day()
|
|
print('Success!')
|
|
|
|
.. raw:: html
|
|
|
|
</details>
|
|
|
|
A solution to this problem is provided :doc:`here <solutions/mlk-day-rrule>`.
|
|
|
|
|
|
Next Monday meeting
|
|
-------------------
|
|
|
|
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>`_.
|
|
|
|
**Test Script**
|
|
|
|
To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks.
|
|
|
|
.. raw:: html
|
|
|
|
<details>
|
|
|
|
|
|
.. code-block:: python3
|
|
|
|
# --------- YOUR CODE -------------- #
|
|
from dateutil import relativedelta
|
|
|
|
def next_monday(dt):
|
|
<<YOUR CODE HERE>>
|
|
|
|
# ---------------------------------- #
|
|
|
|
from datetime import datetime
|
|
from dateutil import tz
|
|
|
|
NEXT_MONDAY_CASES = [
|
|
(datetime(2018, 4, 11, 14, 30, 15, 123456),
|
|
datetime(2018, 4, 16, 10, 0)),
|
|
(datetime(2018, 4, 16, 10, 0),
|
|
datetime(2018, 4, 16, 10, 0)),
|
|
(datetime(2018, 4, 16, 10, 30),
|
|
datetime(2018, 4, 23, 10, 0)),
|
|
(datetime(2018, 4, 14, 9, 30, tzinfo=tz.gettz('America/New_York')),
|
|
datetime(2018, 4, 16, 10, 0, tzinfo=tz.gettz('America/New_York'))),
|
|
]
|
|
|
|
def test_next_monday_1():
|
|
for dt_in, dt_out in NEXT_MONDAY_CASES:
|
|
assert next_monday(dt_in) == dt_out
|
|
|
|
if __name__ == "__main__":
|
|
test_next_monday_1()
|
|
print('Success!')
|
|
|
|
.. raw:: html
|
|
|
|
</details>
|
|
|
|
|
|
Parsing a local tzname
|
|
----------------------
|
|
|
|
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.
|
|
|
|
Problem 1
|
|
*********
|
|
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.
|
|
|
|
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.
|
|
|
|
**Test Script**
|
|
|
|
To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks.
|
|
|
|
.. raw:: html
|
|
|
|
<details>
|
|
|
|
|
|
.. code-block:: python3
|
|
|
|
# --------- YOUR CODE -------------- #
|
|
from dateutil.parser import parse
|
|
from dateutil import tz
|
|
|
|
def parse_func_us_jp_ind():
|
|
<<YOUR CODE HERE>>
|
|
|
|
# ---------------------------------- #
|
|
|
|
from dateutil import tz
|
|
from datetime import datetime
|
|
|
|
|
|
PARSE_TZ_TEST_DATETIMES = [
|
|
datetime(2018, 1, 1, 12, 0),
|
|
datetime(2018, 3, 20, 2, 0),
|
|
datetime(2018, 5, 12, 3, 30),
|
|
datetime(2014, 9, 1, 23)
|
|
]
|
|
|
|
PARSE_TZ_TEST_ZONES = [
|
|
tz.gettz('America/New_York'),
|
|
tz.gettz('America/Chicago'),
|
|
tz.gettz('America/Denver'),
|
|
tz.gettz('America/Los_Angeles'),
|
|
tz.gettz('Asia/Kolkata'),
|
|
tz.gettz('Asia/Tokyo'),
|
|
]
|
|
|
|
def test_parse():
|
|
for tzi in PARSE_TZ_TEST_ZONES:
|
|
for dt in PARSE_TZ_TEST_DATETIMES:
|
|
dt_exp = dt.replace(tzinfo=tzi)
|
|
dtstr = dt_exp.strftime('%Y-%m-%d %H:%M:%S %Z')
|
|
|
|
dt_act = parse_func_us_jp_ind(dtstr)
|
|
assert dt_act == dt_exp
|
|
assert dt_act.tzinfo is dt_exp.tzinfo
|
|
|
|
if __name__ == "__main__":
|
|
test_parse()
|
|
print('Success!')
|
|
|
|
.. raw:: html
|
|
|
|
</details>
|
|
|
|
|
|
Problem 2
|
|
*********
|
|
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.
|
|
|
|
**Test Script**
|
|
|
|
To solve this exercise, copy-paste this script into a document, change anything between the ``--- YOUR CODE ---`` comment blocks.
|
|
|
|
|
|
.. raw:: html
|
|
|
|
<details>
|
|
|
|
.. code-block:: python3
|
|
|
|
# --------- YOUR CODE -------------- #
|
|
from dateutil.parser import parse
|
|
from dateutil import tz
|
|
|
|
def parse_func_ind_ire():
|
|
<<YOUR CODE HERE>>
|
|
|
|
# ---------------------------------- #
|
|
ISRAEL = tz.gettz('Asia/Jerusalem')
|
|
INDIA = tz.gettz('Asia/Kolkata')
|
|
PARSE_IXT_TEST_CASE = [
|
|
('2018-02-03 12:00 IST+02:00', datetime(2018, 2, 3, 12, tzinfo=ISRAEL)),
|
|
('2018-06-14 12:00 IDT+03:00', datetime(2018, 6, 14, 12, tzinfo=ISRAEL)),
|
|
('2018-06-14 12:00 IST', datetime(2018, 6, 14, 12, tzinfo=INDIA)),
|
|
('2018-06-14 12:00 IST+05:30', datetime(2018, 6, 14, 12, tzinfo=INDIA)),
|
|
('2018-02-03 12:00 IST', datetime(2018, 2, 3, 12, tzinfo=INDIA)),
|
|
]
|
|
|
|
|
|
def test_parse_ixt():
|
|
for dtstr, dt_exp in PARSE_IXT_TEST_CASE:
|
|
dt_act = parse_func_ind_ire(dtstr)
|
|
assert dt_act == dt_exp, (dt_act, dt_exp)
|
|
assert dt_act.tzinfo is dt_exp.tzinfo, (dt_act, dt_exp)
|
|
|
|
if __name__ == "__main__":
|
|
test_parse_ixt()
|
|
print('Success!')
|
|
|
|
.. raw:: html
|
|
|
|
</details>
|
|
|