8.7. Datetime Timedelta

8.7.1. Setup

>>> from datetime import datetime, date, timedelta

8.7.2. Timedelta Object

>>> td = timedelta(
...     weeks=1,
...     days=2,
...     hours=3,
...     minutes=4,
...     seconds=5,
...     microseconds=6
... )
>>>
>>> td
datetime.timedelta(days=9, seconds=11045, microseconds=6)

8.7.3. Timedelta Attributes

>>> td.days
9
>>>
>>> td.seconds
11045
>>>
>>> td.microseconds
6
>>>
>>> td.total_seconds()
788645.000006

8.7.4. Date Delta

Shifting date objects:

>>> birthdate = date(2000, 1, 1)
>>> today = date(2025, 1, 1)
>>>
>>> td = today - birthdate
>>>
>>> repr(td)
'datetime.timedelta(days=9132)'
>>>
>>> str(td)
'9132 days, 0:00:00'

8.7.5. Datetime Delta

>>> gagarin = datetime(1961, 4, 12, 6, 7)
>>> armstrong = datetime(1969, 7, 21, 2, 56, 15)
>>>
>>> td = armstrong - gagarin
>>>
>>> repr(td)
'datetime.timedelta(days=3021, seconds=74955)'
>>>
>>> str(td)
'3021 days, 20:49:15'
>>> td.days
3021
>>>
>>> td.seconds
74955
>>>
>>> td.total_seconds()  # (days * seconds per day + seconds)
261089355.0

8.7.6. Simple Time Shift

>>> from datetime import timedelta, datetime
>>>
>>>
>>> gagarin = datetime(1961, 4, 12)
>>>
>>> gagarin - timedelta(minutes=15)
datetime.datetime(1961, 4, 11, 23, 45)
>>>
>>> gagarin + timedelta(minutes=10)
datetime.datetime(1961, 4, 12, 0, 10)
>>> from datetime import timedelta, datetime
>>>
>>>
>>> armstrong = datetime(1969, 7, 21, 2, 56, 15)
>>>
>>> armstrong - timedelta(hours=21)
datetime.datetime(1969, 7, 20, 5, 56, 15)
>>>
>>> armstrong + timedelta(hours=5)
datetime.datetime(1969, 7, 21, 7, 56, 15)
>>> from datetime import timedelta, date
>>>
>>>
>>> sputnik = date(1957, 10, 4)
>>>
>>> sputnik + timedelta(days=5)
datetime.date(1957, 10, 9)
>>>
>>> sputnik - timedelta(days=3)
datetime.date(1957, 10, 1)
>>> from datetime import datetime, timedelta
>>>
>>>
>>> gagarin = datetime(1961, 4, 12)
>>>
>>> gagarin + timedelta(weeks=2)
datetime.datetime(1961, 4, 26, 0, 0)
>>>
>>> gagarin - timedelta(weeks=3)
datetime.datetime(1961, 3, 22, 0, 0)

8.7.7. Complex Shifts

>>> from datetime import timedelta, datetime
>>>
>>>
>>> armstrong = datetime(1969, 7, 21, 2, 56, 15)
>>>
>>> armstrong - timedelta(days=2, hours=21)
datetime.datetime(1969, 7, 18, 5, 56, 15)
>>> from datetime import timedelta, datetime
>>>
>>>
>>> armstrong = datetime(1969, 7, 21, 2, 56, 15)
>>>
>>> duration = timedelta(
...     weeks=3,
...     days=2,
...     hours=21,
...     minutes=5,
...     seconds=12,
...     milliseconds=10,
...     microseconds=55)
>>>
>>> duration
datetime.timedelta(days=23, seconds=75912, microseconds=10055)
>>>
>>> armstrong - duration
datetime.datetime(1969, 6, 27, 5, 51, 2, 989945)

8.7.8. Month Shifts

>>> from datetime import timedelta, date
>>>
>>>
>>> MONTH = timedelta(days=30.4375)
>>>
>>> gagarin = date(1961, 4, 12)
>>> gagarin - MONTH
datetime.date(1961, 3, 13)
>>> from calendar import _monthlen as monthlen
>>> from datetime import timedelta, date
>>>
>>>
>>> def month_before(dt):
...     MONTH = monthlen(dt.year, dt.month)
...     return dt - timedelta(days=MONTH)
>>>
>>>
>>> gagarin = date(1961, 4, 12)
>>> month_before(gagarin)
datetime.date(1961, 3, 13)

8.7.9. Duration

  • Period between two datetimes

>>> from datetime import datetime
>>>
>>>
>>> SECOND = 1
>>> MINUTE = 60 * SECOND
>>> HOUR = 60 * MINUTE
>>> DAY = 24 * HOUR
>>> MONTH = 30.4375 * DAY  # Average days a month in solar calendar
>>> YEAR = 365.25 * DAY  # Solar calendar
>>>
>>>
>>> def duration(td):
...     years, seconds = divmod(td.total_seconds(), YEAR)
...     months, seconds = divmod(seconds, MONTH)
...     days, seconds = divmod(seconds, DAY)
...     hours, seconds = divmod(td.seconds, HOUR)
...     minutes, seconds = divmod(seconds, MINUTE)
...     return {
...         'years': int(years),
...         'months': int(months),
...         'days': int(days),
...         'hours': int(hours),
...         'minutes': int(minutes),
...         'seconds': int(seconds)}
>>>
>>>
>>> gagarin = datetime(1961, 4, 12, 6, 7)
>>> armstrong = datetime(1969, 7, 21, 2, 56, 15)
>>>
>>> td = armstrong - gagarin
>>> td
datetime.timedelta(days=3021, seconds=74955)
>>>
>>> duration(td)
{'years': 8, 'months': 3, 'days': 8, 'hours': 20, 'minutes': 49, 'seconds': 15}

8.7.10. Further Reading

8.7.11. Assignments

# %% About
# - Name: Datetime Timedelta Timeshift
# - Difficulty: easy
# - Lines: 1
# - Minutes: 2

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define `result: date` with DATE + 4 days
# 2. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj `result: date` z DATE + 4 dni
# 2. Uruchom doctesty - wszystkie muszą się powieść

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> assert type(result) is date, \
'Variable `result` has invalid type, must be a date'

>>> result
datetime.date(2000, 1, 5)
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports
from datetime import date, timedelta

# %% Types
result: date

# %% Data
DATE = date(2000, 1, 1)

# %% Result
result = ...

# %% About
# - Name: Datetime Timedelta Age
# - Difficulty: easy
# - Lines: 2
# - Minutes: 2

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define `result: int` age of a person born on `DATE`
# 2. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj `result: int` z wiekiem osoby urodzonej w `DATE`
# 2. Uruchom doctesty - wszystkie muszą się powieść

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> assert type(result) is int, \
'Variable `result` has invalid type, must be a int'

>>> result
25
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports
from datetime import date

# %% Types
result: int

# %% Data
DAY = 1
YEAR = 365.25 * DAY
DATE = date(2000, 1, 1)

# %% Result
result = ...

# %% About
# - Name: Datetime Timedelta Duration
# - Difficulty: easy
# - Lines: 2
# - Minutes: 2

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Calculate how many years passed between Gagarin's launch
#    and Armstrong's first step on the Moon
# 2. Assume:
#    - year = 365.25 days
#    - month = 30.4375 days
# 3. Result round to two decimal places
# 4. Run doctests - all must succeed

# %% Polish
# 1. Wylicz ile lat upłynęło między startem Gagarina
#    a pierwszym krokiem Armstronga na Księżycu
# 2. Uwzględnij założenie:
#    - rok = 365.25 dni
#    - miesiąc = 30.4375 dni
# 3. Rezultat zaokrąglij do dwóch miejsc po przecinku
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> assert type(result) is float, \
'Variable `result` has invalid type, must be a float'

>>> result
8.27
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports
from datetime import datetime

# %% Types
result: float

# %% Data
DAY = 1
YEAR = 365.25 * DAY

GAGARIN = datetime(1961, 4, 12, 6, 7)
ARMSTRONG = datetime(1969, 7, 21, 2, 56, 15)

# %% Result
result = ...

# FIXME: Verify solution

# %% About
# - Name: Datetime Timedelta Period
# - Difficulty: easy
# - Lines: 2
# - Minutes: 5

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Between the first flight to space and the first step on the moon passed:
#    - 8 years
#    - 3 months
#    - 8 days
#    - 20 hours
#    - 49 minutes
#    - 15 seconds
# 2. Assumption:
#    - year = 365.25 days
#    - month = 30.4375 days
# 3. Define `result: timedelta` representing given period
# 4. Run doctests - all must succeed

# %% Polish
# 1. Między pierwszym lotem w kosmos a pierwszym krokiem na Księżycu minęło:
#    - 8 lat
#    - 3 miesięcy
#    - 8 dni
#    - 20 godzin
#    - 49 minut
#    - 15 sekund
# 2. Założenie:
#    - rok = 365.25 dni
#    - miesiąc = 30.4375 dni
# 3. Zdefiniuj `result: timedelta` reprezentujące dany okres
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> assert type(result) is timedelta, \
'Variable `result` has invalid type, must be a timedelta'

>>> result
datetime.timedelta(days=3022, seconds=15555)
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports
from datetime import timedelta

# %% Types
result: timedelta

# %% Data
SECOND = 1
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE
DAY = 24 * HOUR
MONTH = 30.4375 * DAY
YEAR = 365.25 * DAY

# %% Result
result = ...

# %% About
# - Name: Datetime Timedelta Dict
# - Difficulty: easy
# - Lines: 11
# - Minutes: 5

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Variable `DATA` is the time between Gagarin launch and Armstrong
#    first step on the Moon
# 2. Assume:
#    - year = 365.25 days
#    - month = 30.4375 days
# 3. Define `result: dict[str, int]` representing period
# 4. Result should be: 8 years, 3 months, 8 days, 20 hours, 49 minutes, 15 seconds
# 5. Run doctests - all must succeed

# %% Polish
# 1. Zmienna `DATA`, to czas który upłynął między startem Gagarina
#    a pierwszym krokiem Armstronga na Księżycu
# 2. Uwzględnij założenie:
#    - rok = 365.25 dni
#    - miesiąc = 30.4375 dni
# 3. Zdefiniuj `result: dict[str, int]` reprezentujący okres
# 4. Wynik powinien być: 8 years, 3 months, 8 days, 20 hours, 49 minutes, 15 seconds
# 5. Uruchom doctesty - wszystkie muszą się powieść

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> assert type(result) is dict, \
'Variable `result` has invalid type, must be a dict'

>>> result.keys()
dict_keys(['years', 'months', 'days', 'hours', 'minutes', 'seconds'])

>>> assert all(type(value) is int for value in result.values()), \
'All elements in `result` must be an int'

>>> result  # doctest: +NORMALIZE_WHITESPACE
{'years': 8,
 'months': 3,
 'days': 8,
 'hours': 20,
 'minutes': 49,
 'seconds': 15}
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports
from datetime import timedelta

# %% Types
result: dict[str, int]

# %% Data
SECOND = 1
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE
DAY = 24 * HOUR
MONTH = 30.4375 * DAY
YEAR = 365.25 * DAY

DATA = timedelta(days=3022, seconds=15555)

# %% Result
result = {
    'years': ...,
    'months': ...,
    'days': ...,
    'hours': ...,
    'minutes': ...,
    'seconds': ...,
}