Nächstes Kapitel: Python, Pandas and Timeseries
Python, Datum und Zeit
Python Standard-Module für Zeit-Daten
Python bietet reichlich Funktionalität, um mit Datums- und Zeit-Daten umzugehen. Die Standard-Bibliotheken enthalten folgende Module:
time
calendar
datetime
Diese Module bieten Klassen zur Manipulation von simplen und komplexen Datums- und Zeit-Daten.
Speziell die datetime
-Klasse ist sehr wichtig für die Timeseries in Pandas.
Die wichtigsten Module in Python, um mit Zeiten zu arbeiten, sind time
,
calendar
und datetime
.
Das datetime
-Modul bietet diverse Klassen, Methoden und Funktionen für die Arbeit mit Daten, Zeiten und Zeit-Intervallen. Dafür stehen folgende Klassen zur Verfügung:
- Die Instanzen der
date
-Klasse können Daten innerhalb der Jahre zwischen 1 und 9999 abbilden. - Eine Instanz der
datetime
-Klasse besteht sowohl aus dem Datum, als auch aus der Zeit. - Die
time
-Klasse implementiert Zeit-Objekte. - Die
timedelta
-Klasse wird verwendet zur Differenzbildung zwischen zwei Zeit- oder Datums-Objekten. - Die
tzinfo
-Klasse dient der Implementierung von Zeitzonen für Zeit- und Datums-Objekten.
Wir starten mit dem date-Objekt.
Die date-Klasse
from datetime import date x = date(1993, 12, 14) print(x)
1993-12-14
Wir können Datums-Objekte zwischen dem 01. Januar 0001 und dem 31. Dezember 9999 instanziieren. Über die Attribute min
und max
kann dies ermittelt werden:
from datetime import date print(date.min) print(date.max)
0001-01-01 9999-12-31
Wir können diverse Methoden auf das obige date
-Objekt anwenden. Das proleptische Gregorianische Ordinal liefert die Methode toordinal
. Der proleptische gregorianische Kalender besteht aus der Erweiterung des gregorianischen Kalenders rückwärts über seine Einführung im Jahre 1582 hinaus. In der Ordinalen Numerierung entspricht somit dem Tag 1 der 1. Januar des Jahres 1:
x = date(1, 1, 1) # 1. Januar 1 print(x.toordinal()) x = date(1, 1, 2) # 2. Januar 1 print(x.toordinal()) print(x.today()) print(x.today().toordinal())
1 2 2019-02-21 737111
Aus einem Ordinal kann das Datum mit der Klassen-Methode fromordinal
wieder herausgerechnet werden:
print(date.fromordinal(726952))
1991-04-30
Wenn Sie den Wochentag eines bestimmten Tages wissen möchten, kann dies mit der Methode weekday
berechnet werden. weekday
liefert Zahlen zwischen 0
(Montag) und 6
(Sonntag) zurück.
print(x.weekday())
1
print(date.today())
2019-02-21
Über die Attribute können wir auf den Tag, den Monat und das Jahr eines Date-Objektes zugreifen:
print(x.day) print(x.month) print(x.year)
2 1 1
Die time-Klasse
Die time
-Klasse ist gleich organisiert wie die date
-Klasse.
from datetime import time t = time(15, 6, 23) print(t)
15:06:23
Die möglichen Zeiten liegen zwischen:
print(time.min) print(time.max)
00:00:00 23:59:59.999999
Der Zugriff auf Stunde, Minute und Sekunde:
print(t.hour, t.minute, t.second)
15 6 23
Jede Komponente eines Zeit-Objektes kann durch replace()
geändert werden:
t = t.replace(hour=11, minute=59) print(t)
11:59:23
Wir können einen Datums-String in C-Style generieren, entsprechend der ctime
-Funktion in C:
print(x.ctime())
Tue Jan 2 00:00:00 0001
Die datetime-Klasse
Das datetime
-Modul bietet uns Funktionen und Methoden zur Manipulation von Datums- und Zeit-Objekten. Weiterhin stellt es Funktionalitäten zur Verfügung für arithmetische Operationen für Datums- und Zeit-Objekte, z.B. Addition und Subtraktion. Ein weiterer Fokus der Implementierung liegt auf der Extrahierung von Attributen.
Es gibt zwei Arten von Datums- und Zeit-Objekten:
- naive
- aware
Wenn ein Zeit-Objekt 'naive' ist, enthält es keine Informationen für den Vergleich oder die Lokalisation gegenüber anderen Datums- oder Zeit-Objekten. Die Semantik, falls das 'naive'-Objekt einer bestimmten Zeitzone entspricht (wie beispielsweise UTC, lokale Zeit, etc.), ist in der Logik des Programs verankert.
Auf der anderen Seite hat ein 'aware'-Objekt Informationen über die Zeitzone. Somit kann es gegenüber anderen 'aware'-Objekten lokalisiert werden.
Wie können Sie herausfinden, ob ein datetime-Objekt t
'aware' ist?
t
ist 'aware', wenn t.tzinfo
nicht None ist und t.tzinfo.utcoffset(t)
nicht None ist.
Beide Bedingungen müssen erfüllt sein.
Demgegenüber ist das Objekt t
'naive', wenn t.tzinfo
oder t.tzinfo.utcoffset(t)
None ist.
Erstellen wir ein datetime-Objekt:
from datetime import datetime t = datetime(2017, 4, 19, 16, 31, 0) print(t)
2017-04-19 16:31:00
t
ist naive, weil folgender Ausdruck True
ist:
print(t.tzinfo == None)
True
Wir erstellen ein 'aware' datetime-Objekt vom aktuellen Datum. Dafür benötigen wir das Modul pytz
. pytz
ist ein Modul, welches die 'Olsen-Zeitzonen-Datenbank' in Python bereitstellt. Die Olsen-Zeitzonen werden nahezu komplett durch dieses Modul unterstützt.
from datetime import datetime import pytz t = datetime.now(pytz.utc)
Wir sehen, dass sowohl t.tzinfo
als auch t.tzinfo.utcoffset(t)
nicht None
sind und t
somit ein 'aware'-Objekt ist:
print(t.tzinfo, t.tzinfo.utcoffset(t))
UTC 0:00:00
from datetime import datetime, timedelta as delta ndays = 15 start = datetime(1991, 4, 30) dates = [start - delta(days=x) for x in range(0, ndays)] datesDer obige Code führt zu folgendem Ergebnis:
[datetime.datetime(1991, 4, 30, 0, 0), datetime.datetime(1991, 4, 29, 0, 0), datetime.datetime(1991, 4, 28, 0, 0), datetime.datetime(1991, 4, 27, 0, 0), datetime.datetime(1991, 4, 26, 0, 0), datetime.datetime(1991, 4, 25, 0, 0), datetime.datetime(1991, 4, 24, 0, 0), datetime.datetime(1991, 4, 23, 0, 0), datetime.datetime(1991, 4, 22, 0, 0), datetime.datetime(1991, 4, 21, 0, 0), datetime.datetime(1991, 4, 20, 0, 0), datetime.datetime(1991, 4, 19, 0, 0), datetime.datetime(1991, 4, 18, 0, 0), datetime.datetime(1991, 4, 17, 0, 0), datetime.datetime(1991, 4, 16, 0, 0)]
Unterschied zwischen Zeiten
Schauen wir was passiert, wenn wir datetime
-Objekte voneinander subtrahieren:
from datetime import datetime delta = datetime(1993, 12, 14) - datetime(1991, 4, 30) print(delta, type(delta))
959 days, 0:00:00 <class 'datetime.timedelta'>
Das Ergebnis der Subtraktion der beiden datetime
-Objekte ist ein timedelta
-Objekt.
Über das Attribut days
können wir die Tage der Differenz auslesen:
print(delta.days)
959
t1 = datetime(2017, 1, 31, 14, 17) t2 = datetime(2015, 12, 15, 16, 59) delta = t1 - t2 print(delta.days, delta.seconds)
412 76680
Es ist möglich, ein timedelta
-Objekt von einem anderen datetime
-Objekt zu subtrahieren oder es zu addieren (in Tagen), um ein neues datetime
-Objekt zu berechnen:
from datetime import datetime, timedelta d1 = datetime(1991, 4, 30) d2 = d1 + timedelta(10) print(d2) print(d2 - d1) d3 = d1 - timedelta(100) print(d3) d4 = d1 - 2 * timedelta(50) print(d4)
1991-05-10 00:00:00 10 days, 0:00:00 1991-01-20 00:00:00 1991-01-20 00:00:00
Ebenso können timedelta
-Objekte auch in Tagen und Minuten zu datetime
-Objekten addiert oder voneinander subtrahiert werden:
from datetime import datetime, timedelta d1 = datetime(1991, 4, 30) d2 = d1 + timedelta(10,100) print(d2) print(d2 - d1)
1991-05-10 00:01:40 10 days, 0:01:40
Wandlung von datetime-Objekten in Strings
Der einfachste Weg ein datetime
-Objekt als String darzustellen ist die str
-Methode.
s = str(d1) print(s)
1991-04-30 00:00:00
Wandlung mit strftime
Der Methodenaufruf datetime.strftime(format)
liefert einen String zurück, welcher die Zeit und das Datum repräsentiert, jedoch durch ein explizites Format bestimmt wird.
Ein komplette Liste von möglichen Formatierungen kann hier (strftime) eingesehen werden:
print(d1.strftime('%Y-%m-%d')) print("Wochentag: " + d1.strftime('%a')) print("Wochentag ausgeschrieben: " + d1.strftime('%A')) # Weekday as a decimal number, where 0 is Sunday # and 6 is Saturday print("Wochentag als Dezimalzahl: " + d1.strftime('%w'))
1991-04-30 Wochentag: Tue Wochentag ausgeschrieben: Tuesday Wochentag als Dezimalzahl: 2
Formatierung von Monaten:
# Day of the month as a zero-padded decimal number. # 01, 02, ..., 31 print(d1.strftime('%d')) # Month as locale’s abbreviated name. # Jan, Feb, ..., Dec (en_US); # Jan, Feb, ..., Dez (de_DE) print(d1.strftime('%b')) # Month as locale’s full name. # January, February, ..., December (en_US); # Januar, Februar, ..., Dezember (de_DE) print(d1.strftime('%B')) # Month as a zero-padded decimal number. # 01, 02, ..., 12 print(d1.strftime('%m'))
30 Apr April 04
Ausgabe in Landessprache
Wir haben bereits gesehen, dass die Datumsausgaben in Englisch erfolgt sind. Im Folgenden geben wir ein Datum auf die im Vereinigten Königreich gebräuchlichste Art aus:
from datetime import datetime, timedelta d1 = datetime(1993, 12, 14) print(d1.strftime('%d %B %Y')) print("Nur in Zahlen:") print(d1.strftime('%d/%m/%Y')) print("Auf US Art:") print(d1.strftime('%m/%d/%Y')) print(f"It was a {d1.strftime('%A'):s}!")
14 December 1993 Nur in Zahlen: 14/12/1993 Auf US Art: 12/14/1993 It was a Tuesday!
Eine häufig gestellte Frage lautet, wie man diese Ausgaben in Landessprache ausgeben kann. Zunächst ist es wichtig, das locale
-Modul zu importieren:
from datetime import datetime, timedelta import locale # Umstellung auf Deutsch: locale.setlocale(locale.LC_ALL, 'de_DE.utf8') d1 = datetime(1993, 12, 14) print(d1.strftime('%d. %B %Y')) print("Nur in Zahlen:") print(d1.strftime('%d.%m.%Y')) print(f"Der {d1.strftime('%d.%m.%Y'):s} war ein {d1.strftime('%A'):s}!") # und nun in Französisch: locale.setlocale(locale.LC_ALL, 'fr_FR.utf8') d1 = datetime(1993, 12, 14) print(d1.strftime('%d %B %Y')) print("Seulement en nombre:") print(d1.strftime('%d.%m.%Y')) print(f"Le {d1.strftime('%d %m %Y'):s} était un {d1.strftime('%A'):s}!")
14. Dezember 1993 Nur in Zahlen: 14.12.1993 Der 14.12.1993 war ein Dienstag! 14 décembre 1993 Seulement en nombre: 14.12.1993 Le 14 12 1993 était un mardi!
Anmerkung:
Die länderspezifischen Ausgaben der obigen Beispiele funktionieren nur, falls 'de_DE.utf8' und 'fr_FR.utf8' im Betriebssystem installiert sind. Unter Ubuntu kann man diese wie folgt installieren:
sudo locale-gen fr_FR.UTF-8
und
sudo locale-gen de_DE.UTF-8
datetime-Objekte aus Strings erstellen
Wir können strptime
nutzen, um neue datetime
-Objekte aus Strings zu erstellen, welche Datum und Zeit beinhalten. Die Argumente von strptime
sind der String, welcher geparst werden soll, und die Format-Spezifikation.
from datetime import datetime t = datetime.strptime("30 12 1999", "%d %m %Y") print(t)
1999-12-30 00:00:00
dt = "2007-03-04T21:08:12" datetime.strptime( dt, "%Y-%m-%dT%H:%M:%S" )Der obige Code liefert folgendes Ergebnis:
datetime.datetime(2007, 3, 4, 21, 8, 12)
import locale locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') dt = '12/24/1957 4:03:29 AM' dt = datetime.strptime(dt, '%m/%d/%Y %I:%M:%S %p') dtDer obige Python-Code liefert Folgendes:
datetime.datetime(1957, 12, 24, 4, 3, 29)
Auf einer Linux-Maschine können wir einen englischen Datumsstring generieren mit dem Kommando
LC_ALL=en_EN.utf8 date
.
dt = 'Wed Apr 12 20:29:53 CEST 2017' dt = datetime.strptime(dt, '%a %b %d %H:%M:%S %Z %Y') print(dt)
2017-04-12 20:29:53
Obwohl datetime.strptime()
eine einfache Möglichkeit ist, ein Datum mit einem bekannten Format zu parsen, kann es doch kompliziert sein, für neue Datumsformate jedes Mal eine neue Spezifikation zu erstellen.
Für das Parsen ist die Nutzung der Methode dateutil.parser
besser:
from dateutil.parser import parse parse('2011-01-03')Der obige Python-Code liefert folgendes Ergebnis:
datetime.datetime(2011, 1, 3, 0, 0)
parse('Wed Apr 12 20:29:53 CEST 2017')Führt man obigen Code aus, erhält man folgende Ausgabe:
datetime.datetime(2017, 4, 12, 20, 29, 53, tzinfo=tzlocal())
Nächstes Kapitel: Python, Pandas and Timeseries