7.7. Datetime Timedelta

7.7.1. Timedelta object

Shifting datetime objects:

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

7.7.2. 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)

7.7.3. 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)

7.7.4. 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)

7.7.5. 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}

7.7.6. Further Reading

7.7.7. Assignments

# %% 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

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

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

# %% 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ść

# %% Tests
"""
>>> 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)
"""

from datetime import date, timedelta


DATE = date(2000, 1, 1)


# Add 4 days to DATE
# type: date
result = ...


# %% 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

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

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

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

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

# %% Tests
"""
>>> 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
"""

from datetime import date


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


# age of a person born on `DATE`
# type: int
result = ...


# %% 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

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

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

# %% English
# 1. How old was Yuri Gagarin when he was launched to space?
# 2. Result round to full years
# 3. Run doctests - all must succeed

# %% Polish
# 1. Ile miał lat Juri Gagarin kiedy wystartował w kosmos?
# 2. Rezultat zaokrąglij do pełnych lat
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Tests
"""
>>> 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
27
"""

from datetime import date, datetime


DAY = 1
YEAR = 365.25 * DAY

BIRTHDATE = date(1934, 3, 9)
LAUNCH_DATE = date(1961, 4, 12)

# Gagarin's age when he was launched to space
# type: int
result = ...


# %% 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

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

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

# %% English
# 1. How old was Neil Armstrong when he made a first step on the Moon?
# 2. Result round to full years
# 3. Mind, that there are two different objects: `date` and `datetime`
# 4. Run doctests - all must succeed

# %% Polish
# 1. Ile lat miał Neil Armstrong kiedy zrobił pierwszy krok na Księżycu?
# 2. Rezultat zaokrąglij do pełnych lat
# 3. Zwróć uwagę, że tam są dwa różne obiekty: `date` i `datetime`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Tests
"""
>>> 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
38
"""

from datetime import date, datetime


DAY = 1
YEAR = 365.25 * DAY

BIRTHDATE = date(1930, 8, 5)
FIRST_STEP = datetime(1969, 7, 21, 2, 56, 15)

# Armstrong's age when he made a first step on the Moon
# type: int
result = ...


# %% 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

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

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

# %% 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. Podany jest 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. Rezultat zaokrąglij do dwóch miejsc po przecinku
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Tests
"""
>>> 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
"""

from datetime import datetime


DAY = 1
YEAR = 365.25 * DAY

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

# Number of years rounded to 2 decimal place
# type: float
result = ...


# FIXME: Verify solution

# %% 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

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

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

# %% English
# 1. Between the first flight to space and the first step on the moon passed:
#    - 8 years
#    - 3 months
#    - 8 days
#    - 13 hours
#    - 19 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ść

# %% Tests
"""
>>> 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)
"""

from datetime import timedelta


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


# - 8 years
# - 3 months
# - 8 days
# - 20 hours
# - 49 minutes
# - 15 seconds
# type: timedelta
result = ...


# %% 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

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

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

# %% 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ść

# %% Tests
"""
>>> 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}
"""

from datetime import timedelta


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)


# `DATA` is the time between Gagarin launch and Armstrong
# first step on the Moon
# Assume:
# - year = 365.25 days
# - month = 30.4375 days
# Define `result: dict[str, int]` representing period
# 8 years, 3 months, 8 days, 20 hours, 49 minutes, 15 seconds
# dict[str, int]
result = {
    'years': ...,
    'months': ...,
    'days': ...,
    'hours': ...,
    'minutes': ...,
    'seconds': ...,
}