12. Datetime

12.1. calendar

Code Listing 12.1. HTML Calendar
import calendar

html = calendar.HTMLCalendar().formatmonth(2017, 12)
print(html)

12.2. time

Code Listing 12.2. Time sleep function
import time

time.sleep(2)
Code Listing 12.3. Get timestamp
import time

time.time()
# 1496737953.0712671

time.time()
# 1496737954.3189602

time.time()
# 1496737954.9830358
Code Listing 12.4. Time formatting
from time import gmtime
from time import strftime

strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())
# 'Thu, 28 Jun 2017 14:17:15 +0000'
Code Listing 12.5. Time parsing
import time

time.strptime("30 Nov 00", "%d %b %y")
# time.struct_time(
#     tm_year=2017,
#     tm_mon=11,
#     tm_mday=30,
#     tm_hour=0,
#     tm_min=0,
#     tm_sec=0,
#     tm_wday=3,
#     tm_yday=335,
#     tm_isdst=-1
# )
Code Listing 12.6. Timezone information for time
import time

print(time.timezone)
# -3600

print(time.tzname)
# ('CET', 'CEST')

12.3. timeit

Code Listing 12.7. Timeit
python3 -m timeit '"-".join(str(n) for n in range(100))'
# 10000 loops, best of 3: 30.2 usec per loop

python3 -m timeit '"-".join([str(n) for n in range(100)])'
# 10000 loops, best of 3: 27.5 usec per loop

# python3 -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 3: 23.2 usec per loop
Code Listing 12.8. Timeit
import timeit


timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
# 0.3018611848820001

timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
# 0.2727368790656328

timeit.timeit('"-".join(map(str, range(100)))', number=10000)
# 0.23702679807320237

12.4. datetime

12.4.1. Tworzenie obiektu date i datetime

Code Listing 12.9. Creating date and datetime objects
import datetime

now = datetime.datetime.now()
today = datetime.date.today()

date = datetime.date(1961, 4, 12)
dt = datetime.datetime(1969, 7, 21, 14, 56, 15)
midnight = datetime.datetime(1957, 10, 4)

12.4.2. Różne formaty dat

https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior

  • ‘15.12.2017’
  • ‘15/12/2017’
  • ‘15 grudnia 2017’
  • ‘15 grudzień 2017’
  • ‘12/15/17’
  • ‘December 15, 2017’
  • ‘2017-12-15’
Code Listing 12.10. Datetime formatting as string
import datetime

now = datetime.datetime.now()
print(f'Now is {now:%Y-%m-%d %H:%M}!')
# Now is 2017-12-19 17:40!

out = now.strftime('%A, %B %d, %I:%M %p')
print(out)
# Tuesday, December 19, 05:40 PM
Code Listing 12.11. Datetime parsing from string
import datetime


sputnik = '4 October 1957 19:28:34 UTC'

out = datetime.datetime.strptime(sputnik, '%d %B %Y %H:%M:%S %Z')
# datetime.datetime(1957, 10, 4, 19, 28, 34)

print(out)
# 1957-10-04 19:28:34
Directive Meaning Example
%a Weekday as locale’s abbreviated name. Sun, Mon, …, Sat
%A Weekday as locale’s full name.
Sunday, Monday, …,
Saturday (en_US);
Sonntag, Montag, …,
Samstag (de_DE)
%w Weekday as a decimal number, where 0 is Sunday and 6 is Saturday. 0, 1, …, 6
%d Day of the month as a zero-padded decimal number. 01, 02, …, 31
%b Month as locale’s abbreviated name.
Jan, Feb, …, Dec
(en_US);
Jan, Feb, …, Dez
(de_DE)
%B Month as locale’s full name.
January, February,
…, December (en_US);
Januar, Februar, …,
Dezember (de_DE)
%m Month as a zero-padded decimal number. 01, 02, …, 12
%y Year without century as a zero-padded decimal number. 00, 01, …, 99
%Y Year with century as a decimal number. 0001, 0002, …, 2013, 2014, …, 9998, 9999
%H Hour (24-hour clock) as a zero-padded decimal number. 00, 01, …, 23
%I Hour (12-hour clock) as a zero-padded decimal number. 01, 02, …, 12
%p Locale’s equivalent of either AM or PM. AM, PM (en_US); am, pm (de_DE)
%M Minute as a zero-padded decimal number. 00, 01, …, 59
%S Second as a zero-padded decimal number. 00, 01, …, 59
%f Microsecond as a decimal number, zero-padded on the left. 000000, 000001, …, 999999
%z UTC offset in the form +HHMM or -HHMM (empty string if the object is naive). (empty), +0000, -0400, +1030
%Z Time zone name (empty string if the object is naive). (empty), UTC, EST, CST
%j Day of the year as a zero-padded decimal number. 001, 002, …, 366
%U Week number of the year (Sunday as the first day of the week) as a zero padded decimal number. All days in a new year preceding the first Sunday are considered to be in week 0. 00, 01, …, 53
%W Week number of the year (Monday as the first day of the week) as a decimal number. All days in a new year preceding the first Monday are considered to be in week 0. 00, 01, …, 53
%c Locale’s appropriate date and time representation.
Tue Aug 16 21:30:00
1988 (en_US);
Di 16 Aug 21:30:00
1988 (de_DE)
%x Locale’s appropriate date representation. 08/16/88 (None); 08/16/1988 (en_US); 16.08.1988 (de_DE)
%X Locale’s appropriate time representation. 21:30:00 (en_US); 21:30:00 (de_DE)
%% A literal '%' character. %

Several additional directives not required by the C89 standard are included for convenience. These parameters all correspond to ISO 8601 date values. These may not be available on all platforms when used with the strftime method. The ISO 8601 year and ISO 8601 week directives are not interchangeable with the year and week number directives above. Calling strptime with incomplete or ambiguous ISO 8601 directives will raise a ValueError.

Directive Meaning Example
%G ISO 8601 year with century representing the year that contains the greater part of the ISO week (%V). 0001, 0002, …, 2013, 2014, …, 9998, 9999
%u ISO 8601 weekday as a decimal number where 1 is Monday. 1, 2, …, 7
%V ISO 8601 week as a decimal number with Monday as the first day of the week. Week 01 is the week containing Jan 4. 01, 02, …, 53

12.4.3. Przesunięcia czasu (dodawanie i odejmowanie)

Code Listing 12.12. Shifting datetimes
import datetime

dt1 = datetime.datetime(1961, 4, 12, 6, 7)
dt2 = datetime.datetime(1969, 7, 21, 14, 56, 15)

duration = dt2 - dt1
# datetime.timedelta(3022, 31755)

print(duration)
# 3022 days, 8:49:15

duration.seconds
# 31755

duration.days
# 3022

duration.total_seconds()
# 261132555.0  # bo duration.days * ilosc sekund na dzien + duration.seconds

YEAR = 365
years = duration.days / YEAR
# 8.27945205479452
Code Listing 12.13. Substract time from datetimes
import datetime


datetime.datetime.now() - datetime.timedelta(hours=3)
datetime.date(1961, 4, 12) - datetime.timedelta(days=3)


def month_ago(date):
    """
    >>> month_ago(datetime.datetime(1969, 7, 21, 14, 56, 15))
    datetime.datetime(1969, 6, 21, 14, 56, 15)
    """
    return date - datetime.timedelta(days=30)

12.4.4. Konwersja Timestamp Unix Timestamp -> Microsoft Timestamp

Code Listing 12.14. Konwersja Timestamp Unix Timestamp -> Microsoft Timestamp
import datetime
import time


def datetime_to_mstimestamp(date):
    """
    Active Direcotry has different approach to create timestamp than Unix.
    Here's a function to convert the Unix timestamp to the AD one.

    >>> datetime_to_mstimestamp(datetime.datetime(2000, 1, 1, 0, 0))
    125911548000000000
    """
    timestamp = int(time.mktime(date.timetuple()))
    magic_number = 116444736000000000
    return timestamp * 10000000 + magic_number


def mstimestamp_to_datetime(mstimestamp):
    """
    Active Direcotry has different approach to create timestamp than Unix.
    Here's a function to convert AD timestamp to the Unix one.

    >>> mstimestamp_to_datetime(130567328471235643)
    datetime.datetime(2014, 10, 2, 16, 14, 7, 123563)
    """
    magic_number = 11644473600
    return datetime.datetime.fromtimestamp(
        mstimestamp / 10000000 - magic_number)

12.4.5. Strefy czasowe

Code Listing 12.15. Make timezone aware object from naive datetime
import datetime

# timezone naive - nieświadome
datetime.datetime.now()
datetime.datetime(1957, 10, 4, 19, 28, 34)


# timezone aware - świadome
datetime.datetime.now().replace(tzinfo=datetime.timezone.utc)
datetime.datetime(1957, 10, 4, 19, 28, 34).replace(tzinfo=datetime.timezone.utc)

12.5. pytz

Code Listing 12.16. pytz brings the Olson tz database into Python.
import pytz

utc = pytz.utc
print(utc.zone)
#'UTC'

eastern = pytz.timezone('US/Eastern')
print(eastern.zone)
# 'US/Eastern'

amsterdam = pytz.timezone('Europe/Amsterdam')
print(amsterdam.zone)
# 'Europe/Amsterdam'

This library allows accurate and cross platform timezone calculations using Python 2.4 or higher. It also solves the issue of ambiguous times at the end of daylight saving time, which you can read more about in the Python Library Reference (datetime.tzinfo).

12.6. Zadania kontrolne

12.6.1. Manipulacja datami

  1. Użytkownik poda wykorzystując input() dwie następujące daty w formacie jak poniżej:

    • April 12, 1961 2:07 local time (ALMT Timezone)
    • 07/21/69 2:56:15 AM UTC
  2. Przedstaw daty jako obiekt datetime. I wyświetl je w formacie ISO.

  3. Odejmij obie daty od siebie. Ile lat i miesięcy minęło między wydarzeniami?

  4. Do dzisiejszej daty dodaj ten sam czas, który Ci wyszedł w poprzednim zadaniu.

  5. Wyświetl samą datę (bez czasu).

  6. Ile będziesz miał wtedy lat?

Zadanie z gwiazdką:
 
  • Co to za daty, które podał użytkownik?
  • Uwzględnij strefy czasowe.
Podpowiedź:
  • wykorzystaj try i except przy strptime