3.3. Datetime Time Deltas

3.3.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()       # 261089355.0 (days * seconds per day + seconds)

3.3.2. Time Shift

3.3.3. Simple Shifts

Simple timedelta shifts:

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)

Simple timedelta shifts:

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)

Simple timedelta shifts:

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)

Simple timedelta shifts:

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)

3.3.4. Complex Shifts

Complex timedelta 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)

Complex timedelta shifts:

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)
# datetime.timedelta(days=23, seconds=75912, microseconds=10055)

between_dates = armstrong - duration
# datetime.datetime(1969, 6, 27, 5, 51, 2, 989945)

3.3.5. Month Shifts

Subtract month from datetime:

from datetime import timedelta, date


MONTH = timedelta(days=30.436875)

gagarin = date(1961, 4, 12)
gagarin - MONTH
# datetime.date(1961, 3, 13)

Subtract month from datetime:

from calendar import 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)

3.3.6. Duration

Duration between two datetimes:

from datetime import datetime

SECOND = 1
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE
DAY = 24 * HOUR
MONTH = 30.436875 * DAY  # Average days a month in solar calendar
YEAR = 365.2425 * DAY  # Solar calendar

def duration(dt):
    years, seconds = divmod(dt.total_seconds(), YEAR)
    months, seconds = divmod(seconds, MONTH)
    days, seconds = divmod(seconds, DAY)
    hours, seconds = divmod(dt.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)

dt = armstrong - gagarin
# datetime.timedelta(days=3021, seconds=74955)

duration(dt)
# {'years': 8, 'months': 3, 'days': 8, 'hours': 20, 'minutes': 49, 'seconds': 15}

3.3.8. Assignments

Code 3.10. Solution
"""
* Assignment: Datetime Timedelta Duration
* Complexity: easy
* Lines of code: 2 lines
* Time: 3 min

English:
    1. Use data from "Given" section (see below)
    2. Calculate how many years passed between Gagarin's launch
       and Armstrong's first step on the Moon
    3. Assume:
        a. year = 365.2425 days
        b. month = 30.436875 days
    4. Result round to one decimal place
    5. Run doctests - all must succeed

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    2. Podany jest czas, który upłynął między startem Gagarina a pierwszym krokiem Armstronga na Księżycu
    3. Uwzględnij założenie:
        a. rok = 365.2425 dni
        b. miesiąc = 30.436875 dni
    4. Rezultat zaokrąglij jednego miejsca po przecinku
    5. Uruchom doctesty - wszystkie muszą się powieść

Tests:
    >>> import sys; sys.tracebacklimit = 0

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

    >>> result
    8.3
"""


# Given
from datetime import datetime, timedelta


DAY = 1
MONTH = 30.436875 * DAY
YEAR = 365.2425 * DAY

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

Code 3.11. Solution
"""
* Assignment: Datetime Timedelta Age
* Complexity: easy
* Lines of code: 6 lines
* Time: 11 min

English:
    1. Use data from "Given" section (see below)
    2. How old was Yuri Gagarin when he was launched to space?
    3. How old was Neil Armstrong when he made a first step on the Moon?
    4. Result round to full years
    5. Mind, that there are two different objects: `date` and `datetime`
    6. Run doctests - all must succeed

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    2. Ile miał lat Juri Gagarin kiedy wystartował w kosmos?
    3. Ile lat miał Neil Armstrong kiedy zrobił pierwszy krok na Księżycu?
    4. Rezultat zaokrąglij do pełnych lat
    5. Mind, that there are two different objects: `date` and `datetime`
    6. Uruchom doctesty - wszystkie muszą się powieść

Tests:
    >>> import sys; sys.tracebacklimit = 0

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

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

    >>> gagarin_age
    27

    >>> armstrong_age
    39
"""


# Given
from datetime import datetime, date


DAY = 1
MONTH = 30.436875 * DAY
YEAR = 365.2425 * DAY

GAGARIN_BIRTHDAY = date(1934, 3, 9)
GAGARIN_LAUNCH = datetime(1961, 4, 12, 6, 7)
ARMSTRONG_BIRTHDAY = date(1930, 8, 5)
ARMSTRONG_STEP = datetime(1969, 7, 21, 2, 56, 15)

gagarin_age = ...  # int: Gagarin's age when he was launched to space
armstrong_age = ...  # int: Armstrong's age when he made a first step on the Moon


Code 3.12. Solution
"""
* Assignment: Datetime Timedelta Period
* Complexity: easy
* Lines of code: 2 lines
* Time: 8 min

English:
    1. Use data from "Given" section (see below)
    2. Given period is the time between Gagarin launch and Armstrong first step on the Moon:
        * 8 years
        * 3 months
        * 8 days
        * 20 hours
        * 49 minutes
        * 15 seconds
    3. Assume:
        a. year = 365.2425 days
        b. month = 30.436875 days
    4. Define `result: timedelta` representing given period
    X. Run doctests - all must succeed

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    2. Podany jest czas, który upłynął między startem Gagarina a pierwszym krokiem Armstronga na Księżycu:
        * 8 lat
        * 3 miesięcy
        * 8 dni
        * 20 godzin
        * 49 minut
        * 15 sekund
    3. Uwzględnij założenie:
        a. rok = 365.2425 dni
        b. miesiąc = 30.436875 dni
    4. Zdefiniuj `result: timedelta` reprezentujące dany okres
    X. Uruchom doctesty - wszystkie muszą się powieść


Tests:
    >>> import sys; sys.tracebacklimit = 0

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

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


# Given
from datetime import timedelta


SECOND = 1
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE
DAY = 24 * HOUR
MONTH = 30.436875 * DAY
YEAR = 365.2425 * DAY

# 8 years
# 3 months
# 8 days
# 20 hours
# 49 minutes
# 15 seconds

result = ...  # timedelta: representing given period


Code 3.13. Solution
"""
* Assignment: Datetime Timedelta Dict
* Complexity: easy
* Lines of code: 13 lines
* Time: 13 min

English:
    1. Use data from "Given" section (see below)
    2. Given period `DATA` is the time between Gagarin launch and Armstrong first step on the Moon
    3. Assume:
        a. year = 365.2425 days
        b. month = 30.436875 days
    4. Define `result: dict[str, int]` representing period
    X. Run doctests - all must succeed

Polish:
    1. Użyj danych z sekcji "Given" (patrz poniżej)
    2. Podany jest okres `DATA`, który upłynął między startem Gagarina a pierwszym krokiem Armstronga na Księżycu
    3. Uwzględnij założenie:
        a. rok = 365.2425 dni
        b. miesiąc = 30.436875 dni
    4. Zdefiniuj `result: dict[str, int]` reprezentujący okres
    X. Uruchom doctesty - wszystkie muszą się powieść

Given:
    * 8 years
    * 3 months
    * 8 days
    * 20 hours
    * 49 minutes
    * 15 seconds

Tests:
    >>> import sys; sys.tracebacklimit = 0

    >>> 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
    {'years': 8, 'months': 3, 'days': 9, 'hours': 6, 'minutes': 50, 'seconds': 9}
"""


# Given
from datetime import timedelta


SECOND = 1
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE
DAY = 24 * HOUR
MONTH = 30.436875 * DAY
YEAR = 365.2425 * DAY

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

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