Lekce 15 - Datum a čas v Pythonu podruhé - Knihovna datetime
V minulé lekci, Datum a čas v Pythonu, jsme si představili knihovny time
a calendar
.
V následujícím tutoriálu objektově orientovaného programování
v Pythonu se podíváme na práci s modulem datetime
,
který se vedle modulů time
a calendar
používá pro
práci s datem a časem a podporuje příjemnější, objektový přístup.
Oproti knihovně time
je datetime
mnohem bohatší a
nabízí širší paletu funkcí a vlastností. Současně ale také platí, že
mnoho funkcí (metod) mají obě knihovny buď přímo společných (názvem,
syntaxí i výstupem), nebo se jen velmi mírně liší. V lekci je tedy
nebudeme opakovat a více se zaměříme na objektový přístup k datu a
času.
Knihovna datetime
Knihovna datetime
pracuje s vlastními specializovanými
datetime
objekty. To nám snadno umožní od sebe jednotlivá data
například odečítat nebo je navzájem porovnávat bez nutnosti zaobírání
se počtem sekund od roku 1970 nebo indexy ve výstupu ve formě tuple. Nyní si
ukážeme, jak se tyto objekty zakládají a jak s nimi budeme dál pracovat v
jednotlivých modulech.
Třída datetime
Velmi významnou třídou v této knihovně je stejnojmenná třída
datetime
a její opět stejnojmenná metoda
datetime()
. Tu budeme v praxi používat pro vytváření
instancí, se kterými budeme dále pracovat. Také poskytuje užitečné
metody, které budeme hojně využívat.
Běžnou konvencí, kterou dodržujeme i v našich tutoriálech,
je pojmenování třídy velkým písmenem, a tedy bychom měli třídu
pojmenovat Datetime
. Vývojáři Pythonu bohužel na konvence v
názvech modulů a tříd často příliš neberou ohled. Aby náš text lekce
odpovídal skutečnému kódu, budeme na třídu odkazovat jako na
datetime
s malým počátečním písmenem. Jinak by se text lekce
od kódu lišil a bylo by to matoucí.
Metody třídy datetime
Podívejme se nyní na důležité metody, které nám třída
datetime
poskytuje. Jak už jsme zmínili v úvodu lekce, mnoho
metod je stejných nebo velmi podobných s funkcemi modulu
time
.
Metoda datetime()
Metoda datetime()
přijímá jako argumenty v daném pořadí
údaje: rok, měsíc, den, hodina, minuta, sekunda a mikrosekunda. Vytvořme si
instanci data a času z určitého roku, měsíce a dne:
from datetime import datetime # Pro jednodušší kód si importujeme rovnou třídu Datetime.
# Vyhneme se tím opakovaným zápisům datetime.datetime(...).
datum = datetime(2023, 10, 23)
print(datum)
Metoda now()
Metoda now()
nám jednoduše umožní získat aktuální datum a
čas:
from datetime import datetime
dnes = datetime.now()
print(dnes)
Metoda vytvoří instanci třídy datetime
, ve které jsou
uloženy aktuální informace k datu. K jednotlivým údajům se dostaneme velmi
lehce a to pomocí atributů year
, month
,
day
, hour
, minute
a
second
:
from datetime import datetime
dnes = datetime.now()
print("Datum:")
print(f"Rok: {dnes.year}")
print(f"Měsíc: {dnes.month}")
print(f"Den: {dnes.day}")
print(f"Čas: {dnes.hour}:{dnes.minute}:{dnes.second}")
Metoda weekday()
Metoda, kterou voláme na instanci třídy datetime
, nám
zjistí den v týdnu, ke kterému tato instance patří. Zkusme si ji zavolat na
aktuálním datu a času:
from datetime import datetime
dnes = datetime.now()
# Seznam dnů v týdnu
dny_v_tydnu = ["pondělí", "úterý", "středa", "čtvrtek", "pátek", "sobota", "neděle"]
den = dny_v_tydnu[dnes.weekday()]
print(f"Dnes je {den}.")
V této metodě se pro nás ukrývá mnoho možností, a je pouze na nás, jaký formát pro získávání data a času si zvolíme.
Knihovna datetime
dále mimo jiné obsahuje také například
metody strftime()
a strptime()
. Tyto metody (a
další) jsou prakticky identické se stejnojmennými funkcemi z modulu
time
, kterými jsme se zabývali v lekci Datum a čas v Pythonu. Ke
srovnání je nejlepší nahlédnout do oficiální dokumentace knihovny
datetime.
Práce s datem
Práce s daty je jedním z nejčastějších úkolů v programování. Ať
už potřebujeme porovnat dvě data nebo spočítat počet dní mezi nimi,
knihovna datetime
nám nabízí efektivní nástroje pro tyto
úkoly. Výhodou knihovny datetime
je její objektový přístup k
reprezentaci času a data. Díky tomu, že všechna data ukládáme jako
instance té samé třídy, máme tedy možnost provádět s daty různé
aritmetické operace, jako je sčítání a odčítání, nebo porovnávat data
mezi sebou. V této kapitole se podíváme na několik základních operací a
funkcí, které nám datetime
nabízí pro práci s daty, a
ukážeme si, jak je efektivně využít v praxi.
Aritmetické operace s datem
Nejprve se zaměříme na základní matematické operace jako jsou sčítání a odčítání:
from datetime import datetime
dnes = datetime.now() # založíme aktuální datum
tehdy = datetime(2000, 1, 1) # založíme datum 1.1.2000
ubehly_cas = dnes - tehdy # odečteme data od sebe
print(ubehly_cas)
V tomto případě proměnná ubehly_cas
obsahuje počet dnů,
hodin, minut a sekund, které uběhly od začátku 3. tisíciletí do dnešního
dne. Za podobným účelem máme ještě k dispozici metodu
total_seconds()
, která vrátí počet sekund uběhlých v daném
intervalu.
Porovnávání
Dvě data můžeme mezi sebou i porovnávat a to obyčejnými operátory, které používáme při porovnávání čísel:
from datetime import datetime
dnes = datetime.now()
tehdy = datetime(2000, 1, 1)
print(dnes > tehdy) # vrátí True
print(dnes == tehdy) # vrátí False
Změna vytvořeného data
Pokud potřebujeme rychle a snadno změnit již vytvořené datum, použijeme
metodu replace()
. Zvyšme si rok a den na objektu
datetime
o 1
:
from datetime import datetime
dnes = datetime.now()
zmena_roku = dnes.replace(year = dnes.year + 1)
zmena_dne = dnes.replace(day = dnes.day + 1)
print(f"Přidáme rok navíc a budeme mít rok {zmena_roku.year}.")
print(f"Přidáme den navíc a budeme mít {zmena_dne.day}.{dnes.month}.")
Metoda replace()
funguje na jakémkoliv časovém objektu - jen
v ní musíme přesně specifikovat, co chceme měnit na jakou hodnotu. Jde
pouze o změnu hodnoty již založené proměnné.
Pokud je dnes.day
poslední den měsíce (např.
31. ledna nebo 30. dubna), přidání jednoho dne způsobí
ValueError
.
Podobné problémy nicméně řeší třída timedelta
.
Podívejme se na ni.
Třída timedelta
Pro další možnosti práce s časem je zde třída timedelta
.
Třída timedelta
nám umožňuje vyjádřit časový interval,
což může zahrnovat dny, sekundy, mikrosekundy a podobně. S instancemi
timedelta
lze podobně jako v případě třídy
datetime
provádět různé aritmetické operace, například
přidávat je k instancím datetime
nebo odečítat je od sebe.
Pokud od sebe dvě data například odečteme, získáme instanci třídy
timedelta
, což není konkrétní datum, ale interval (rozdíl)
mezi nějakými dvěma daty. Tento objekt si založíme a snadno zjistíme,
jaký den bude za 10 dní:
from datetime import datetime
from datetime import timedelta
dnes = datetime.now()
deset_dnu = timedelta(10) # vytvoříme objekt timedelta s posunem o 10 dní
za_10_dni = dnes + deset_dnu
pred_10_dny = dnes - deset_dnu
print(f"Dnes je: {dnes}")
print(f"Za 10 dní bude: {za_10_dni}")
print(f"Před 10 dny bylo: {pred_10_dny}")
Třída timedelta
také řeší problém s přechodem z měsíce
na měsíc. Pokud interval přesáhne plný (nebo minimální) počet dní v
daném měsíci, třída automaticky přejde na další (předchozí) měsíc v
pořadí.
Konstruktor timedelta()
nemusíme vždy použít s celými dny.
Pokud chceme pracovat s jinou hodnotou, máme tu možnost. Při zakládání
objektu timedelta
máme možnost navolit mnoho argumentů. Pokud
explicitně neuvedeme názvy argumentů, tak v uvedeném pořadí:
- days,
- seconds,
- microseconds,
- milliseconds,
- minutes,
- hours,
- weeks.
Čekali bychom, že největší jednotky (jako týdny nebo dny) budou v
argumentech uvedeny jako první, následované menšími jednotkami (hodiny,
minuty atd.). Proč je pořadí argumentů takto podivné? To je otázka, na
kterou není jednoznačná odpověď. Je možné, že to je historická
záležitost nebo designová volba vývojářů Pythonu, která může být
založena na interním zpracování nebo jiných aspektech implementace. Nebo se
zkrátka někdo opravdu špatně vyspal V každém případě, když
vytváříme instanci
timedelta
, je dobré si zvyknout explicitně
uvádět jména argumentů. Zvýšíme tím čitelnost kódu a eliminujeme
potenciální zmatek:
interval = timedelta(weeks=2, days=3, hours=1)
Třída timedelta
bohužel nemá v argumentech
dostupný počet let a měsíců, protože rok ani měsíc nejsou plnohodnotné
časové jednotky a nemají pevně daný počet dní (některé roky jsou
přestupné).
Ořezání data o čas
Všechny metody, které jsme si dosud zmínili, pracují s objekty
datetime
(datum a čas). Pokud bychom chtěli využívat pouze
datum, je vhodné místo tohoto použít objekt date
. Ten nenese
informaci o času, která by nám jinak mohla znepříjemňovat třeba
porovnávání. Objekt date
získáme z třídy
datetime
pomocí metody date()
:
from datetime import date
from datetime import timedelta
dnes = date.today()
print(f"Dnešní datum: {dnes}")
print(f"Za 10 dní bude: {dnes + timedelta(10)}")
print(f"Před 10 dny bylo: {dnes - timedelta(10)}")
Není na tom nic složitého. Jediná změna od datetime
je v
použití metody today()
, která přímo nahrazuje
now()
. Veškeré metody používané výše v lekci jsou s tímto
formátem naprosto kompatibilní. Pokud tedy ve svých programech nepotřebujeme
časové informace, můžeme je poměrně snadno vynechat.
Souběžné použití
time
a datetime
Pokud se rozhodneme v jednom programu využívat současně moduly
time
a datetime
, na první pohled nám to přinese
určité výhody. Zejména širokou škálu funkcí a metod obou modulů. Avšak
je zde jedno velké "ale".
Oba moduly mají, jak už jsme si zmínili, mnoho funkcí a metod se stejným
názvem, například strftime()
. Pokud oba moduly naimportujeme
kompletně pomocí import time
a import datetime
,
budeme muset uvádět, z kterého modulu chceme danou funkci nebo metodu
používat. Třeba takto - time.strftime()
nebo
datetime.datetime.strftime()
. To povede k velmi nepřehlednému
kódu a pravděpodobně také ke zbytečným chybám. Proto je velmi vhodné
při importech použít aliasy nebo třídy importovat přímo:
from datetime import datetime as dt from datetime import timedelta
Díky tomu si budeme jistí, jakou funkci či metodu z jakého modulu skutečně voláme.
V následujícím kvízu, Kvíz - Datum a čas v Pythonu, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.