# 4.6. Datetime Time Deltas¶

## 4.6.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


## 4.6.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)


## 4.6.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)


## 4.6.4. Month Shifts¶

>>> from datetime import timedelta, date
>>>
>>>
>>> MONTH = timedelta(days=30.436875)
>>>
>>> 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)


## 4.6.5. Duration¶

• Period 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
>>> dt
datetime.timedelta(days=3021, seconds=74955)
>>>
>>> duration(dt)
{'years': 8, 'months': 3, 'days': 8, 'hours': 20, 'minutes': 49, 'seconds': 15}


## 4.6.7. Assignments¶

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

English:
1. Calculate how many years passed between Gagarin's launch
and Armstrong's first step on the Moon
2. Assume:
a. year = 365.2425 days
b. month = 30.436875 days
3. Result round to one decimal place
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:
a. rok = 365.2425 dni
b. miesiąc = 30.436875 dni
3. Rezultat zaokrąglij jednego miejsca po przecinku
4. 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
"""

from datetime import datetime

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)

# timedelta: Time between GAGARIN and ARMSTRONG
duration = ...

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


"""
* Assignment: Datetime Timedelta Age
* Complexity: easy
* Lines of code: 6 lines
* Time: 5 min

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

Polish:
1. Ile miał lat Juri Gagarin kiedy wystartował w kosmos?
2. Ile lat miał Neil Armstrong kiedy zrobił pierwszy krok na Księżycu?
3. Rezultat zaokrąglij do pełnych lat
4. Mind, that there are two different objects: date and datetime
5. 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
"""

from datetime import date, datetime

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)

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

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


"""
* Assignment: Datetime Timedelta Period
* Complexity: easy
* Lines of code: 2 lines
* Time: 5 min

English:
1. 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
2. Assume:
a. year = 365.2425 days
b. month = 30.436875 days
3. Define result: timedelta representing given period
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:
* 8 lat
* 3 miesięcy
* 8 dni
* 20 godzin
* 49 minut
* 15 sekund
2. Uwzględnij założenie:
a. rok = 365.2425 dni
b. miesiąc = 30.436875 dni
3. Zdefiniuj result: timedelta reprezentujące dany okres
4. 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=10209)
"""

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

# timedelta: representing given period
result = ...


"""
* Assignment: Datetime Timedelta Dict
* Complexity: easy
* Lines of code: 13 lines
* Time: 5 min

English:
1. DATA is the time between Gagarin launch and Armstrong
first step on the Moon
2. Assume:
a. year = 365.2425 days
b. month = 30.436875 days
3. Define result: dict[str, int] representing period
4. Run doctests - all must succeed

Polish:
1. DATA, to czas który upłynął między startem Gagarina
a pierwszym krokiem Armstronga na Księżycu
2. Uwzględnij założenie:
a. rok = 365.2425 dni
b. miesiąc = 30.436875 dni
3. Zdefiniuj result: dict[str, int] reprezentujący okres
4. 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  # doctest: +NORMALIZE_WHITESPACE
{'years': 8,
'months': 3,
'days': 9,
'hours': 6,
'minutes': 50,
'seconds': 9}
"""

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)

# dict[str, int]
result = {
'years': ...,
'months': ...,
'days': ...,
'hours': ...,
'minutes': ...,
'seconds': ...,
}