Python Language
Data i godzina
Szukaj…
Uwagi
Python zapewnia zarówno wbudowane metody, jak i biblioteki zewnętrzne do tworzenia, modyfikowania, analizowania i manipulowania datami i godzinami.
Przetwarzanie ciągu znaków do obiektu datetime rozpoznającego strefę czasową
Python 3.2+ obsługuje format %z
podczas parsowania łańcucha do obiektu datetime
.
Przesunięcie UTC w postaci
+HHMM
lub-HHMM
(pusty ciąg, jeśli obiekt jest naiwny).
import datetime
dt = datetime.datetime.strptime("2016-04-15T08:27:18-0500", "%Y-%m-%dT%H:%M:%S%z")
W przypadku innych wersji Pythona możesz użyć zewnętrznej biblioteki, takiej jak dateutil
, co sprawia, że parsowanie łańcucha ze dateutil
czasową w obiekcie datetime
jest szybkie.
import dateutil.parser
dt = dateutil.parser.parse("2016-04-15T08:27:18-0500")
Zmienna dt
jest teraz obiektem typu datetime
o następującej wartości:
datetime.datetime(2016, 4, 15, 8, 27, 18, tzinfo=tzoffset(None, -18000))
Prosta arytmetyka dat
Daty nie istnieją w oderwaniu. Często zdarza się, że musisz znaleźć czas między datami lub ustalić, która data będzie jutro. Można to osiągnąć za pomocą obiektów timedelta
import datetime
today = datetime.date.today()
print('Today:', today)
yesterday = today - datetime.timedelta(days=1)
print('Yesterday:', yesterday)
tomorrow = today + datetime.timedelta(days=1)
print('Tomorrow:', tomorrow)
print('Time between tomorrow and yesterday:', tomorrow - yesterday)
Spowoduje to uzyskanie wyników podobnych do:
Today: 2016-04-15
Yesterday: 2016-04-14
Tomorrow: 2016-04-16
Difference between tomorrow and yesterday: 2 days, 0:00:00
Podstawowe użycie obiektów datetime
Moduł datetime zawiera trzy podstawowe typy obiektów - datę, godzinę i datę i godzinę.
import datetime
# Date object
today = datetime.date.today()
new_year = datetime.date(2017, 01, 01) #datetime.date(2017, 1, 1)
# Time object
noon = datetime.time(12, 0, 0) #datetime.time(12, 0)
# Current datetime
now = datetime.datetime.now()
# Datetime object
millenium_turn = datetime.datetime(2000, 1, 1, 0, 0, 0) #datetime.datetime(2000, 1, 1, 0, 0)
Operacje arytmetyczne na tych obiektach są obsługiwane tylko w ramach tego samego typu danych, a wykonywanie prostej arytmetyki z wystąpieniami różnych typów spowoduje błąd typu.
# subtraction of noon from today
noon-today
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'datetime.time' and 'datetime.date'
However, it is straightforward to convert between types.
# Do this instead
print('Time since the millenium at midnight: ',
datetime.datetime(today.year, today.month, today.day) - millenium_turn)
# Or this
print('Time since the millenium at noon: ',
datetime.datetime.combine(today, noon) - millenium_turn)
Iteruj po datach
Czasami chcesz iterować w zakresie dat od daty początkowej do pewnej daty końcowej. Możesz to zrobić za pomocą biblioteki datetime
i obiektu timedelta
:
import datetime
# The size of each step in days
day_delta = datetime.timedelta(days=1)
start_date = datetime.date.today()
end_date = start_date + 7*day_delta
for i in range((end_date - start_date).days):
print(start_date + i*day_delta)
Który produkuje:
2016-07-21
2016-07-22
2016-07-23
2016-07-24
2016-07-25
2016-07-26
2016-07-27
Przetwarzanie ciągu o krótkiej nazwie strefy czasowej do obiektu datetime rozpoznającego strefę czasową
Korzystając z biblioteki dateutil
tak jak w poprzednim przykładzie, podczas analizowania znaczników czasowych uwzględniających strefy czasowe , możliwe jest także analizowanie znaczników czasowych z określoną „krótką” nazwą strefy czasowej.
W przypadku dat sformatowanych za pomocą krótkich nazw stref lub skrótów, które są na ogół niejednoznaczne (np. CST, który może być czasem standardowym centralnym, czasem standardowym w Chinach, czasem standardowym na Kubie itp. - więcej informacji można znaleźć tutaj ) lub niekoniecznie jest dostępny w standardowej bazie danych , konieczne jest określenie odwzorowania między skrótem strefy czasowej a obiektem tzinfo
.
from dateutil import tz
from dateutil.parser import parse
ET = tz.gettz('US/Eastern')
CT = tz.gettz('US/Central')
MT = tz.gettz('US/Mountain')
PT = tz.gettz('US/Pacific')
us_tzinfos = {'CST': CT, 'CDT': CT,
'EST': ET, 'EDT': ET,
'MST': MT, 'MDT': MT,
'PST': PT, 'PDT': PT}
dt_est = parse('2014-01-02 04:00:00 EST', tzinfos=us_tzinfos)
dt_pst = parse('2016-03-11 16:00:00 PST', tzinfos=us_tzinfos)
Po uruchomieniu tego:
dt_est
# datetime.datetime(2014, 1, 2, 4, 0, tzinfo=tzfile('/usr/share/zoneinfo/US/Eastern'))
dt_pst
# datetime.datetime(2016, 3, 11, 16, 0, tzinfo=tzfile('/usr/share/zoneinfo/US/Pacific'))
Warto zauważyć, że w przypadku korzystania z pytz
strefę czasową z tej metody, nie będzie on prawidłowo zlokalizowane:
from dateutil.parser import parse
import pytz
EST = pytz.timezone('America/New_York')
dt = parse('2014-02-03 09:17:00 EST', tzinfos={'EST': EST})
To po prostu dołącza pytz
czasową pytz
do pytz
godziny:
dt.tzinfo # Will be in Local Mean Time!
# <DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>
Jeśli używasz tej metody, prawdopodobnie powinieneś ponownie localize
naiwną część daty i godziny po analizie:
dt_fixed = dt.tzinfo.localize(dt.replace(tzinfo=None))
dt_fixed.tzinfo # Now it's EST.
# <DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
Konstruowanie czasów danych uwzględniających strefy czasowe
Domyślnie wszystkie obiekty datetime
są naiwne. Aby uświadomić im strefę czasową, musisz dołączyć obiekt tzinfo
, który zapewnia przesunięcie UTC i skrót strefy czasowej jako funkcję daty i godziny.
Naprawiono przesunięte strefy czasowe
Dla stref czasowych, które są stałym przesunięciem w stosunku do UTC, w Pythonie 3.2+ moduł datetime
udostępnia klasę timezone
, konkretną implementację tzinfo
, która przyjmuje parametr timedelta
i (opcjonalnie) nazwę:
from datetime import datetime, timedelta, timezone
JST = timezone(timedelta(hours=+9))
dt = datetime(2015, 1, 1, 12, 0, 0, tzinfo=JST)
print(dt)
# 2015-01-01 12:00:00+09:00
print(dt.tzname())
# UTC+09:00
dt = datetime(2015, 1, 1, 12, 0, 0, tzinfo=timezone(timedelta(hours=9), 'JST'))
print(dt.tzname)
# 'JST'
W przypadku wersji Python wcześniejszych niż 3.2 konieczne jest użycie biblioteki innej firmy, takiej jak dateutil
. dateutil
zapewnia równoważną klasę, tzoffset
, która (od wersji 2.5.3) przyjmuje argumenty w postaci dateutil.tz.tzoffset(tzname, offset)
, gdzie offset
jest określany w sekundach:
from datetime import datetime, timedelta
from dateutil import tz
JST = tz.tzoffset('JST', 9 * 3600) # 3600 seconds per hour
dt = datetime(2015, 1, 1, 12, 0, tzinfo=JST)
print(dt)
# 2015-01-01 12:00:00+09:00
print(dt.tzname)
# 'JST'
Strefy z czasem letnim
W strefach z czasem letnim standardowe biblioteki Pythona nie zapewniają standardowej klasy, dlatego konieczne jest użycie biblioteki innej firmy. pytz
i dateutil
to popularne biblioteki zapewniające klasy stref czasowych.
Oprócz statycznych stref czasowych dateutil
udostępnia klasy stref czasowych, które wykorzystują czas letni (patrz dokumentacja modułu tz
). Możesz użyć metody tz.gettz()
, aby uzyskać obiekt strefy czasowej, który można następnie przekazać bezpośrednio do konstruktora datetime
:
from datetime import datetime
from dateutil import tz
local = tz.gettz() # Local time
PT = tz.gettz('US/Pacific') # Pacific time
dt_l = datetime(2015, 1, 1, 12, tzinfo=local) # I am in EST
dt_pst = datetime(2015, 1, 1, 12, tzinfo=PT)
dt_pdt = datetime(2015, 7, 1, 12, tzinfo=PT) # DST is handled automatically
print(dt_l)
# 2015-01-01 12:00:00-05:00
print(dt_pst)
# 2015-01-01 12:00:00-08:00
print(dt_pdt)
# 2015-07-01 12:00:00-07:00
PRZESTROGA : Począwszy od wersji 2.5.3, dateutil
nie obsługuje poprawnie niejednoznacznych dateutil
i zawsze dateutil
domyślną datę późniejszą . Nie ma możliwości skonstruowania obiektu ze dateutil
czasową dateutil
reprezentującą na przykład 2015-11-01 1:30 EDT-4
, ponieważ odbywa się to podczas zmiany czasu letniego.
Wszystkie przypadki krawędzi są obsługiwane poprawnie podczas używania pytz
, ale strefy czasowe pytz
nie powinny być bezpośrednio dołączane do stref czasowych za pośrednictwem konstruktora. Zamiast tego należy pytz
strefę czasową pytz
przy użyciu metody localize
strefy czasowej:
from datetime import datetime, timedelta
import pytz
PT = pytz.timezone('US/Pacific')
dt_pst = PT.localize(datetime(2015, 1, 1, 12))
dt_pdt = PT.localize(datetime(2015, 11, 1, 0, 30))
print(dt_pst)
# 2015-01-01 12:00:00-08:00
print(dt_pdt)
# 2015-11-01 00:30:00-07:00
Należy pamiętać, że jeśli wykonujesz arytmetykę czasu i godziny w strefie czasowej pytz
, musisz albo wykonać obliczenia w UTC (jeśli chcesz mieć bezwzględny upływ czasu), albo musisz wywołać normalize()
dla wyniku:
dt_new = dt_pdt + timedelta(hours=3) # This should be 2:30 AM PST
print(dt_new)
# 2015-11-01 03:30:00-07:00
dt_corrected = PT.normalize(dt_new)
print(dt_corrected)
# 2015-11-01 02:30:00-08:00
Rozmyte analizowanie daty i godziny (wyodrębnianie daty i godziny z tekstu)
Możliwe jest wyodrębnienie daty z tekstu za pomocą parsera dateutil
w trybie „rozmytym”, w którym komponenty ciągu nierozpoznanego jako część daty są ignorowane.
from dateutil.parser import parse
dt = parse("Today is January 1, 2047 at 8:21:00AM", fuzzy=True)
print(dt)
dt
jest teraz obiektem datetime
i wydrukowano by datetime.datetime(2047, 1, 1, 8, 21)
.
Przełączanie między strefami czasowymi
Aby przełączać się między strefami czasowymi, potrzebujesz obiektów datetime, które uwzględniają strefy czasowe.
from datetime import datetime
from dateutil import tz
utc = tz.tzutc()
local = tz.tzlocal()
utc_now = datetime.utcnow()
utc_now # Not timezone-aware.
utc_now = utc_now.replace(tzinfo=utc)
utc_now # Timezone-aware.
local_now = utc_now.astimezone(local)
local_now # Converted to local time.
Analiza dowolnego znacznika czasu ISO 8601 przy minimalnej liczbie bibliotek
Python ma ograniczoną obsługę analizowania znaczników czasu ISO 8601. Dla strptime
trzeba dokładnie wiedzieć, co jest w formacie jako powikłanie stringification o. datetime
jest ISO 8601 datownik, z miejsca jako separator i frakcją 6 cyfr:
str(datetime.datetime(2016, 7, 22, 9, 25, 59, 555555))
# '2016-07-22 09:25:59.555555'
ale jeśli ułamkiem jest 0, nie jest generowana żadna część ułamkowa
str(datetime.datetime(2016, 7, 22, 9, 25, 59, 0))
# '2016-07-22 09:25:59'
Ale te 2 formularze wymagają innego formatu czasu strptime
. Co więcej, strptime' does not support at all parsing minute timezones that have a
: in it, thus
2016-07-22 09: 25: 59 + 0300 can be parsed, but the standard format
2016-07-22 09:25:59 +03: 00` nie może.
Jest to pojedynczy plik biblioteki nazywa iso8601
który właściwie analizuje ISO 8601 znaczniki czasu i tylko ich.
Obsługuje ułamki i strefy czasowe, a separator T
wszystkie z jedną funkcją:
import iso8601
iso8601.parse_date('2016-07-22 09:25:59')
# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<iso8601.Utc>)
iso8601.parse_date('2016-07-22 09:25:59+03:00')
# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<FixedOffset '+03:00' ...>)
iso8601.parse_date('2016-07-22 09:25:59Z')
# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<iso8601.Utc>)
iso8601.parse_date('2016-07-22T09:25:59.000111+03:00')
# datetime.datetime(2016, 7, 22, 9, 25, 59, 111, tzinfo=<FixedOffset '+03:00' ...>)
Jeśli nie ustawiono żadnej strefy czasowej, domyślnie iso8601.parse_date
to UTC. Strefę domyślną można zmienić za pomocą argumentu słowa kluczowego default_zone
. W szczególności, jeśli jest to None
zamiast wartości domyślnej, wówczas te znaczniki czasu, które nie mają wyraźnej strefy czasowej, są zwracane jako naiwne czasy danych:
iso8601.parse_date('2016-07-22T09:25:59', default_timezone=None)
# datetime.datetime(2016, 7, 22, 9, 25, 59)
iso8601.parse_date('2016-07-22T09:25:59Z', default_timezone=None)
# datetime.datetime(2016, 7, 22, 9, 25, 59, tzinfo=<iso8601.Utc>)
Konwertowanie znacznika czasu na datę i godzinę
Moduł datetime
może konwertować timestamp
POSIX na obiekt datetime
ITC.
Epoka przypada na północ 1 stycznia 1970 roku.
import time
from datetime import datetime
seconds_since_epoch=time.time() #1469182681.709
utc_date=datetime.utcfromtimestamp(seconds_since_epoch) #datetime.datetime(2016, 7, 22, 10, 18, 1, 709000)
Odejmowanie miesięcy dokładnie od daty
Korzystanie z modułu calendar
import calendar
from datetime import date
def monthdelta(date, delta):
m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12
if not m: m = 12
d = min(date.day, calendar.monthrange(y, m)[1])
return date.replace(day=d,month=m, year=y)
next_month = monthdelta(date.today(), 1) #datetime.date(2016, 10, 23)
Korzystanie z modułu dateutils
import datetime
import dateutil.relativedelta
d = datetime.datetime.strptime("2013-03-31", "%Y-%m-%d")
d2 = d - dateutil.relativedelta.relativedelta(months=1) #datetime.datetime(2013, 2, 28, 0, 0)
Obliczanie różnic czasowych
moduł timedelta
przydaje się do obliczania różnic między czasami:
from datetime import datetime, timedelta
now = datetime.now()
then = datetime(2016, 5, 23) # datetime.datetime(2016, 05, 23, 0, 0, 0)
Określanie czasu jest opcjonalne podczas tworzenia nowego datetime
obiektu
delta = now-then
delta
jest typu timedelta
print(delta.days)
# 60
print(delta.seconds)
# 40826
Aby uzyskać n dzień po i n dzień przed datą, możemy użyć:
n dzień po dacie:
def get_n_days_after_date(date_format="%d %B %Y", add_days=120):
date_n_days_after = datetime.datetime.now() + timedelta(days=add_days)
return date_n_days_after.strftime(date_format)
dzień przed datą:
def get_n_days_before_date(self, date_format="%d %B %Y", days_before=120):
date_n_days_ago = datetime.datetime.now() - timedelta(days=days_before)
return date_n_days_ago.strftime(date_format)
Uzyskaj znacznik czasu ISO 8601
Bez strefy czasowej, z mikrosekundami
from datetime import datetime
datetime.now().isoformat()
# Out: '2016-07-31T23:08:20.886783'
Ze strefą czasową, z mikrosekundami
from datetime import datetime
from dateutil.tz import tzlocal
datetime.now(tzlocal()).isoformat()
# Out: '2016-07-31T23:09:43.535074-07:00'
Ze strefą czasową, bez mikrosekund
from datetime import datetime
from dateutil.tz import tzlocal
datetime.now(tzlocal()).replace(microsecond=0).isoformat()
# Out: '2016-07-31T23:10:30-07:00'
Zobacz ISO 8601, aby uzyskać więcej informacji na temat formatu ISO 8601.