Python Language
Data e ora
Ricerca…
Osservazioni
Python fornisce sia metodi incorporati che librerie esterne per creare, modificare, analizzare e manipolare date e ore.
Analisi di una stringa in un oggetto datetime timezone aware
Python 3.2+ supporta il formato %z
quando analizza una stringa in un oggetto datetime
.
Scostamento UTC nel formato
+HHMM
o-HHMM
(stringa vuota se l'oggetto è ingenuo).
import datetime
dt = datetime.datetime.strptime("2016-04-15T08:27:18-0500", "%Y-%m-%dT%H:%M:%S%z")
Per altre versioni di Python, è possibile utilizzare una libreria esterna come dateutil
, che rende dateutil
analisi di una stringa con fuso orario in un oggetto datetime
.
import dateutil.parser
dt = dateutil.parser.parse("2016-04-15T08:27:18-0500")
La variabile dt
è ora un oggetto datetime
con il seguente valore:
datetime.datetime(2016, 4, 15, 8, 27, 18, tzinfo=tzoffset(None, -18000))
Data semplice aritmetica
Le date non esistono in isolamento. È normale che tu debba trovare la quantità di tempo tra le date o determinare quale sarà la data di domani. Questo può essere realizzato usando oggetti 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)
Ciò produrrà risultati simili a:
Today: 2016-04-15
Yesterday: 2016-04-14
Tomorrow: 2016-04-16
Difference between tomorrow and yesterday: 2 days, 0:00:00
Utilizzo di oggetti datetime di base
Il modulo datetime contiene tre tipi principali di oggetti: data, ora e data / ora.
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)
Le operazioni aritmetiche per questi oggetti sono supportate solo nello stesso tipo di dati e l'esecuzione di operazioni aritmetiche semplici con istanze di tipi diversi comporterà un'eccezione 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)
Scorri le date
A volte si desidera eseguire un'iterazione su un intervallo di date da una data di inizio a una data di fine. Puoi farlo usando la libreria datetime
e timedelta
oggetto 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)
Che produce:
2016-07-21
2016-07-22
2016-07-23
2016-07-24
2016-07-25
2016-07-26
2016-07-27
Analisi di una stringa con un nome breve fuso orario in un oggetto datetime timezone aware
Utilizzando la libreria dateutil
come nell'esempio precedente dateutil
timestamp sensibili al fuso orario , è anche possibile analizzare i timestamp con un nome di fuso orario "breve" specificato.
Per le date formattate con i nomi di zona breve tempo o abbreviazioni, che sono generalmente ambigua (ad esempio CST, che potrebbe essere centrale Standard Time, Cina Standard Time, Cuba Standard Time, ecc - più può essere trovato qui ) o non necessariamente disponibili in un database standard , è necessario specificare una mappatura tra l'abbreviazione del fuso orario e l'oggetto 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)
Dopo aver eseguito questo:
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'))
Vale la pena notare che se si utilizza un pytz
fuso orario con questo metodo, non sarà adeguatamente localizzato:
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})
Questo semplicemente associa il pytz
orario pytz
al datetime:
dt.tzinfo # Will be in Local Mean Time!
# <DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>
Se si utilizza questo metodo, è consigliabile localize
la parte ingenua del datetime dopo l'analisi:
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>)
Costruzione di datetize sensibili al fuso orario
Di default tutti gli oggetti datetime
sono ingenui. Per renderli sensibili al fuso orario, è necessario allegare un oggetto tzinfo
, che fornisce l'offset UTC e l'abbreviazione del fuso orario in funzione della data e dell'ora.
Fissi i fusi orari di offset
Per i fusi orari che sono un offset fisso da UTC, in Python 3.2+, il modulo datetime
fornisce la classe timezone
, un'implementazione concreta di tzinfo
, che accetta un parametro nome timedelta
e (facoltativo):
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'
Per le versioni di Python precedenti alla 3.2, è necessario utilizzare una libreria di terze parti, come dateutil
. dateutil
fornisce una classe equivalente, tzoffset
, che (a partire dalla versione 2.5.3) prende gli argomenti del modulo dateutil.tz.tzoffset(tzname, offset)
, dove l' offset
è specificato in secondi:
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'
Zone con ora legale
Per le zone con ora legale, le librerie standard Python non forniscono una classe standard, quindi è necessario utilizzare una libreria di terze parti. pytz
e dateutil
sono librerie popolari che forniscono classi di fuso orario.
Oltre ai fusi orari statici, dateutil
fornisce classi di fuso orario che utilizzano l'ora legale (consultare la documentazione del modulo tz
). È possibile utilizzare il metodo tz.gettz()
per ottenere un oggetto del fuso orario, che può quindi essere passato direttamente al costruttore 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
ATTENZIONE : A partire dalla versione 2.5.3, dateutil
non gestisce correttamente i datetimes ambigui e sarà sempre predefinito alla data successiva . Non v'è alcun modo per costruire un oggetto con un dateutil
fuso orario che rappresenta, per esempio 2015-11-01 1:30 EDT-4
, poiché questo è in un periodo di transizione legale.
Tutti i casi limite sono gestiti correttamente quando si utilizza pytz
, ma i pytz
orari pytz
non devono essere collegati direttamente ai fusi orari tramite il costruttore. Invece, un pytz
orario di pytz
dovrebbe essere collegato usando il metodo di localize
del fuso orario:
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
Tenere presente che se si esegue l'aritmetica data / ora su un fuso orario pytz
, è necessario eseguire i calcoli in UTC (se si desidera il tempo trascorso assoluto) oppure è necessario chiamare normalize()
sul risultato:
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
Parodia fuzzy parsing (estraendo datetime da un testo)
È possibile estrarre una data da un testo utilizzando l' analizzatore dateutil
in modalità "fuzzy", in cui i componenti della stringa non riconosciuti come parte di una data vengono ignorati.
from dateutil.parser import parse
dt = parse("Today is January 1, 2047 at 8:21:00AM", fuzzy=True)
print(dt)
dt
ora è un oggetto datetime
e datetime.datetime(2047, 1, 1, 8, 21)
stampato.
Passaggio da un fuso orario all'altro
Per passare da un fuso orario all'altro, sono necessari oggetti datetime che sono sensibili al fuso orario.
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.
Analisi di un timestamp arbitrario ISO 8601 con librerie minime
Python ha solo un supporto limitato per l'analisi di timestamp ISO 8601. Per strptime
riguarda la strptime
è necessario sapere esattamente in che formato si trova. Come complicazione, la stringificazione di un datetime
è un timestamp ISO 8601, con spazio come separatore e frazione di 6 cifre:
str(datetime.datetime(2016, 7, 22, 9, 25, 59, 555555))
# '2016-07-22 09:25:59.555555'
ma se la frazione è 0, non viene prodotta alcuna parte frazionaria
str(datetime.datetime(2016, 7, 22, 9, 25, 59, 0))
# '2016-07-22 09:25:59'
Ma queste 2 forme hanno bisogno di un formato diverso per la strptime
. Inoltre, 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` non può.
Esiste una libreria a file singolo chiamata iso8601
che analizza correttamente i timestamp ISO 8601 e solo loro.
Supporta frazioni e fusi orari e il separatore T
tutto con un'unica funzione:
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' ...>)
Se non è impostato un fuso orario, iso8601.parse_date
valore predefinito UTC. La zona predefinita può essere modificata con l'argomento della parola chiave default_zone
. In particolare, se questo è None
invece del valore predefinito, allora quei timestamp che non hanno un fuso orario esplicito vengono restituiti come dati naive invece:
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>)
Conversione del timestamp in data / ora
Il modulo datetime
può convertire un timestamp
POSIX in un oggetto datetime
ITC.
The Epoch è il 1 gennaio 1970 a mezzanotte.
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)
Sottraendo con precisione mesi da una data
Utilizzando il modulo del 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)
Utilizzando il modulo 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)
Calcolo delle differenze di orario
il modulo timedelta
è utile per calcolare le differenze tra i tempi:
from datetime import datetime, timedelta
now = datetime.now()
then = datetime(2016, 5, 23) # datetime.datetime(2016, 05, 23, 0, 0, 0)
La specifica del tempo è facoltativa quando si crea un nuovo oggetto datetime
delta = now-then
delta
è di tipo timedelta
print(delta.days)
# 60
print(delta.seconds)
# 40826
Per ottenere il giorno dopo e il giorno prima della data, potremmo usare:
n giorno dopo data:
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 giorno prima della data:
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)
Ottieni un timestamp ISO 8601
Senza fuso orario, con microsecondi
from datetime import datetime
datetime.now().isoformat()
# Out: '2016-07-31T23:08:20.886783'
Con il fuso orario, con microsecondi
from datetime import datetime
from dateutil.tz import tzlocal
datetime.now(tzlocal()).isoformat()
# Out: '2016-07-31T23:09:43.535074-07:00'
Con il fuso orario, senza microsecondi
from datetime import datetime
from dateutil.tz import tzlocal
datetime.now(tzlocal()).replace(microsecond=0).isoformat()
# Out: '2016-07-31T23:10:30-07:00'
Vedere ISO 8601 per ulteriori informazioni sul formato ISO 8601.