Python Language
Datum och tid
Sök…
Anmärkningar
Python tillhandahåller både inbyggda metoder och externa bibliotek för att skapa, ändra, analysera och manipulera datum och tider.
Parsar en sträng i ett tidszonsmedvetet datatobjekt
Python 3.2+ har stöd för %z
format vid parsning av en sträng i ett datetime
objekt.
UTC-offset i formen
+HHMM
eller-HHMM
(tom sträng om objektet är naivt).
import datetime
dt = datetime.datetime.strptime("2016-04-15T08:27:18-0500", "%Y-%m-%dT%H:%M:%S%z")
För andra versioner av Python kan du använda ett externt bibliotek som dateutil
, vilket gör att parsning av en sträng med tidszon till ett datetime
objekt är snabb.
import dateutil.parser
dt = dateutil.parser.parse("2016-04-15T08:27:18-0500")
dt
variabeln är nu ett datetime
objekt med följande värde:
datetime.datetime(2016, 4, 15, 8, 27, 18, tzinfo=tzoffset(None, -18000))
Enkel datum aritmetik
Datum existerar inte isolerat. Det är vanligt att du måste hitta tiden mellan datum eller bestämma vad som kommer att bli imorgon. Detta kan uppnås med hjälp av timedelta
objekt
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)
Detta ger resultat som liknar:
Today: 2016-04-15
Yesterday: 2016-04-14
Tomorrow: 2016-04-16
Difference between tomorrow and yesterday: 2 days, 0:00:00
Grundläggande användning av datetime-objekt
Datetime-modulen innehåller tre primära typer av objekt - datum, tid och datetime.
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)
Aritmetiska operationer för dessa objekt stöds endast inom samma datatyp och att utföra enkel aritmetik med instanser av olika typer kommer att resultera i en TypeError.
# 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)
Iterera över datum
Ibland vill du upprepa flera datum från ett startdatum till ett slutdatum. Du kan göra det med datetime
bibliotek och timedelta
objekt:
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)
Som producerar:
2016-07-21
2016-07-22
2016-07-23
2016-07-24
2016-07-25
2016-07-26
2016-07-27
Parsar en sträng med ett kort tidszonnamn i ett tidszonsmedvetet datitobjekt
Med hjälp av dateutil
biblioteket som i föregående exempel för att analysera tidszonmedvetna tidsstämplar är det också möjligt att analysera tidsstämplar med ett angivet "kort" tidszonnamn.
För datum formaterade med korta tidszonnamn eller förkortningar, som i allmänhet är tvetydiga (t.ex. CST, som kan vara Central Standard Time, China Standard Time, Cuba Standard Time, etc. - mer kan hittas här ) eller inte nödvändigtvis tillgänglig i en standarddatabas , är det nödvändigt att ange en kartläggning mellan tzinfo
och tzinfo
objekt.
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)
Efter att ha kört detta:
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'))
Det är värt att notera att om du använder en pytz
tidszon med den här metoden, kommer den inte att vara korrekt lokaliserad:
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})
Detta fäster helt enkelt pytz
till datatiden:
dt.tzinfo # Will be in Local Mean Time!
# <DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>
Om du använder den här metoden, bör du nog åter localize
den naiva delen av datetime efter tolkning:
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>)
Konstruera tidszonmedvetna datatider
Som standard är alla datetime
objekt naiva. För att göra dem tidszonmedvetna måste du bifoga ett tzinfo
objekt som ger UTC-offset och tidszonförkortning som en funktion av datum och tid.
Fasta förskjutningstidszoner
För tidszoner som är en fast förskjutning från UTC, i Python 3.2+, datetime
modulen timezone
, en konkret implementering av tzinfo
, som tar en timedelta
och en (valfritt) namnparameter:
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'
För Python-versioner före 3.2 är det nödvändigt att använda ett tredjepartsbibliotek, till exempel dateutil
. dateutil
tillhandahåller en motsvarande klass, tzoffset
, som (från version 2.5.3) tar argument för formen dateutil.tz.tzoffset(tzname, offset)
, där offset
anges i sekunder:
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'
Zoner med sommartid
För zoner med sommartid ger inte Python-standardbibliotek en standardklass, så det är nödvändigt att använda ett tredjepartsbibliotek. pytz
och dateutil
är populära bibliotek som erbjuder tidszonklasser.
Förutom statiska tidszoner tillhandahåller dateutil
som använder sommartid (se dokumentationen för tz
modulen ). Du kan använda tz.gettz()
för att få ett tidszonobjekt som sedan kan skickas direkt till 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
FÖRSIKTIGHET : Från version 2.5.3 hanterar dateutil
inte tvetydiga datatider korrekt och kommer alltid att vara det senare datumet. Det finns inget sätt att konstruera ett objekt med en dateutil
tidszon som representerar, till exempel 2015-11-01 1:30 EDT-4
, eftersom det är under en sommartidövergång.
Alla kanter behandlas korrekt när du använder pytz
, men pytz
tidszoner bör inte fästas direkt på tidzonerna genom konstruktören. Istället pytz
en pytz
tidszon bifogas med hjälp av pytz
localize
:
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
Var medveten om att om du utför datitidens aritmetik på en pytz
varnings-tidszon måste du antingen utföra beräkningarna i UTC (om du vill ha absolut förfluten tid), eller så måste du ringa normalize()
på resultatet:
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
Fuzzy datetime parsing (extrahera datetime ur en text)
Det är möjligt att extrahera ett datum ur en text med hjälp av dateutil
i ett "fuzzy" -läge, där komponenter i strängen som inte erkänns som en del av ett datum ignoreras.
from dateutil.parser import parse
dt = parse("Today is January 1, 2047 at 8:21:00AM", fuzzy=True)
print(dt)
dt
är nu ett datetime
objekt och du skulle se datetime.datetime(2047, 1, 1, 8, 21)
tryckt.
Växla mellan tidszoner
För att växla mellan tidszoner behöver du datatidsobjekt som är tidszonsmedvetna.
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.
Analysera en godtycklig ISO 8601-tidsstämpel med minimala bibliotek
Python har endast begränsat stöd för att analysera ISO 8601-tidsstämplar. För strptime
måste du veta exakt vilket format det är i. Som en komplikation är strängningen av en datetime
en ISO 8601-tidsstämpel, med utrymme som en separator och 6-siffrig bråk:
str(datetime.datetime(2016, 7, 22, 9, 25, 59, 555555))
# '2016-07-22 09:25:59.555555'
men om fraktionen är 0, matas ingen fraktionerad del ut
str(datetime.datetime(2016, 7, 22, 9, 25, 59, 0))
# '2016-07-22 09:25:59'
Men dessa två former behöver ett annat format för strptime
. Dessutom 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` kan inte.
Det finns ett bibliotek med en fil som heter iso8601
som korrekt analyserar ISO 8601-tidsstämplar och bara dem.
Den stöder fraktioner och tidszoner och T
separatorn alla med en enda funktion:
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' ...>)
Om ingen tidszon är inställd, är iso8601.parse_date
standard för UTC. Standardzonen kan ändras med default_zone
. Om detta är None
istället för standard, kommer de tidsstämplar som inte har en tydlig tidszon att returneras som naiva datatider istället:
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>)
Konvertera tidsstämpel till datetime
datetime
modulen kan konvertera en POSIX- timestamp
till ett ITC- datetime
objekt.
Epokchen är 1 januari 1970 midnatt.
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)
Att dra månader från ett datum exakt
Använda 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)
Med hjälp av dateutils
modulen
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)
Beräkna tidsskillnader
timedelta
modulen är praktiskt att beräkna skillnader mellan gånger:
from datetime import datetime, timedelta
now = datetime.now()
then = datetime(2016, 5, 23) # datetime.datetime(2016, 05, 23, 0, 0, 0)
Att ange tid är valfritt när du skapar ett nytt datetime
objekt
delta = now-then
delta
är av typen timedelta
print(delta.days)
# 60
print(delta.seconds)
# 40826
För att få n dag efter och n dag före datum kunde vi använda:
n dag efter datum:
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)
n dag före datum:
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)
Få en ISO 8601-tidsstämpel
Utan tidszon, med mikrosekunder
from datetime import datetime
datetime.now().isoformat()
# Out: '2016-07-31T23:08:20.886783'
Med tidszon, med mikrosekunder
from datetime import datetime
from dateutil.tz import tzlocal
datetime.now(tzlocal()).isoformat()
# Out: '2016-07-31T23:09:43.535074-07:00'
Med tidszon, utan mikrosekunder
from datetime import datetime
from dateutil.tz import tzlocal
datetime.now(tzlocal()).replace(microsecond=0).isoformat()
# Out: '2016-07-31T23:10:30-07:00'
Se ISO 8601 för mer information om ISO 8601-formatet.