Conversione tra datetime, Timestamp e datetime64


290

Come faccio a convertire a numpy.datetime64 oggetto in datetime.datetime(oTimestamp )?

Nel codice seguente, creo oggetti datetime, timestamp e datetime64.

import datetime
import numpy as np
import pandas as pd
dt = datetime.datetime(2012, 5, 1)
# A strange way to extract a Timestamp object, there's surely a better way?
ts = pd.DatetimeIndex([dt])[0]
dt64 = np.datetime64(dt)

In [7]: dt
Out[7]: datetime.datetime(2012, 5, 1, 0, 0)

In [8]: ts
Out[8]: <Timestamp: 2012-05-01 00:00:00>

In [9]: dt64
Out[9]: numpy.datetime64('2012-05-01T01:00:00.000000+0100')

Nota: è facile ottenere il datetime dal timestamp:

In [10]: ts.to_datetime()
Out[10]: datetime.datetime(2012, 5, 1, 0, 0)

Ma come possiamo estrarre datetimeo Timestampda anumpy.datetime64 (dt64 )?

.

Aggiornamento: un esempio un po 'brutto nel mio set di dati (forse l'esempio motivante) sembra essere:

dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100')

quale dovrebbe essere datetime.datetime(2002, 6, 28, 1, 0), e non un lungo (!) ( 1025222400000000000L) ...


2
probabilmente si dovrebbe accettare la risposta di @Wes McKinney che è molto più breve e dovrebbe funzionare su recenti numpy, pandasle versioni.
jfs,

@JFSebastian Hmmm, significa che la risposta è "non passare da np.datetime a datetime" ... basta usare pd.Timestamp (dato che è comunque una sottoclasse di datetime), o se proprio devi davvero usarlo pd.Timestamp(dt64).to_datetime(). Sono ancora un po 'insoddisfatto di questo, ma certamente Wes è meno specifico del mio vecchio problema (e quindi migliore per il mondo)! Grazie ancora per il tempo dedicato a rispondere. :)
Andy Hayden,

La tua domanda dice "o Timestamp" ed Timestampè comunque una datetime(una sottoclasse di) :)
jfs

3
Per chi arriva a questa domanda nel 2017+, guarda la mia risposta qui sotto per un tutorial dettagliato di datetime, datetime64 e Timestamps: stackoverflow.com/a/46921593/3707607
Ted Petrou,

Risposte:


132

Per convertire numpy.datetime64in oggetto datetime che rappresenta l'ora in UTC su numpy-1.8:

>>> from datetime import datetime
>>> import numpy as np
>>> dt = datetime.utcnow()
>>> dt
datetime.datetime(2012, 12, 4, 19, 51, 25, 362455)
>>> dt64 = np.datetime64(dt)
>>> ts = (dt64 - np.datetime64('1970-01-01T00:00:00Z')) / np.timedelta64(1, 's')
>>> ts
1354650685.3624549
>>> datetime.utcfromtimestamp(ts)
datetime.datetime(2012, 12, 4, 19, 51, 25, 362455)
>>> np.__version__
'1.8.0.dev-7b75899'

L'esempio precedente presuppone che un oggetto datetime ingenuo sia interpretato np.datetime64come ora in UTC.


Per convertire datetime in np.datetime64 e back ( numpy-1.6):

>>> np.datetime64(datetime.utcnow()).astype(datetime)
datetime.datetime(2012, 12, 4, 13, 34, 52, 827542)

Funziona sia su un singolo oggetto np.datetime64 che su un array numpy di np.datetime64.

Pensa a np.datetime64 come faresti con np.int8, np.int16, ecc. E applica gli stessi metodi per convertire tra oggetti Python come int, datetime e corrispondenti oggetti numpy.

Il tuo "cattivo esempio" funziona correttamente:

>>> from datetime import datetime
>>> import numpy 
>>> numpy.datetime64('2002-06-28T01:00:00.000000000+0100').astype(datetime)
datetime.datetime(2002, 6, 28, 0, 0)
>>> numpy.__version__
'1.6.2' # current version available via pip install numpy

Posso riprodurre il longvalore su numpy-1.8.0installato come:

pip install git+https://github.com/numpy/numpy.git#egg=numpy-dev

Lo stesso esempio:

>>> from datetime import datetime
>>> import numpy
>>> numpy.datetime64('2002-06-28T01:00:00.000000000+0100').astype(datetime)
1025222400000000000L
>>> numpy.__version__
'1.8.0.dev-7b75899'

Restituisce longperché per numpy.datetime64tipo .astype(datetime)è equivalente a .astype(object)quello restituisce Python intero ( long) sunumpy-1.8 .

Per ottenere l'oggetto datetime è possibile:

>>> dt64.dtype
dtype('<M8[ns]')
>>> ns = 1e-9 # number of seconds in a nanosecond
>>> datetime.utcfromtimestamp(dt64.astype(int) * ns)
datetime.datetime(2002, 6, 28, 0, 0)

Per ottenere datetime64 che utilizza direttamente i secondi:

>>> dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100', 's')
>>> dt64.dtype
dtype('<M8[s]')
>>> datetime.utcfromtimestamp(dt64.astype(int))
datetime.datetime(2002, 6, 28, 0, 0)

I documenti numpy dicono che l'API datetime è sperimentale e potrebbe cambiare nelle future versioni numpy.


1
Temo che questo non sembra funzionare sempre: ad esempio dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100'), che dà un lungo ( 1025222400000000000L) (!)
Andy Hayden,

@hayden: prova type(dt64). dt64.astype(datetime) == datetime.utcfromtimestamp(dt64.astype(int)*1e-6)
jfs,

@JFSebastian type(dt64)è numpy.datetime64ed dt64.astype(datetime)è lo stesso lungo int ...: s
Andy Hayden

@hayden: Qual è la tua versione numpy? Miniera: numpy.__version__->'1.6.1'
jfs

Versione 1.8.0 (in python 2.7.3), se funziona per te suggerisce che è un bug sul mio sistema!
Andy Hayden,

212

Puoi semplicemente usare il costruttore pd.Timestamp. Il diagramma seguente può essere utile per questa e le domande correlate.

Conversioni tra rappresentazioni temporali


2
Bello!!! (Vale la pena ricordare che la situazione è migliorata da quando ho scritto questa domanda, molto lavoro è stato fatto qui :))
Andy Hayden,

107
Basta guardare questo diagramma per dirmi che c'è qualcosa di fondamentalmente sbagliato in tutto questo tempo.
Demented Hedgehog,

4
È molto confuso che pd.to_datetime produrrebbe un TimeStamp se dato il numero di ms o ns, ma produrrebbe un datetime.datetime se dato un datetime.datetime o un np.datetime64 se dato un np.datetime64 ... Perché qualcuno dovrebbe pensi che sia ragionevole?
Mr.WorshipMe

7
@ Mr.WorshipMe Questo diagramma deve essere aggiornato. pd.to_datetimeconverte tutto in pd.Timestamp. Un pd.Timestampoggetto ha il metodo to_pydatetimeper ripristinare un datetime.datetimeoggetto e un to_datetime64metodo in cui convertire np.datetime64.
Ted Petrou,

2
Come posso ottenere una risoluzione più alta di questa immagine?
user3226167,

137

Benvenuto all'inferno.

Puoi semplicemente passare un oggetto datetime64 a pandas.Timestamp:

In [16]: Timestamp(numpy.datetime64('2012-05-01T01:00:00.000000'))
Out[16]: <Timestamp: 2012-05-01 01:00:00>

Ho notato che questo non funziona bene anche se in NumPy 1.6.1:

numpy.datetime64('2012-05-01T01:00:00.000000+0100')

Inoltre, pandas.to_datetimepuò essere utilizzato (questo è fuori dalla versione dev, non ha verificato v0.9.1):

In [24]: pandas.to_datetime('2012-05-01T01:00:00.000000+0100')
Out[24]: datetime.datetime(2012, 5, 1, 1, 0, tzinfo=tzoffset(None, 3600))

5
Dovresti dire che lo issubclass(pd.Timestamp, datetime)è True. E la Timestampclasse stessa ha to_datetime()metodo.
jfs,

7
pd.to_datetime('2012-05-01T01:00:00.000000+0100')ritorna Timestamp('2012-05-01 00:00:00')almeno in panda 0.17.1.
Anton Protopopov,

96

Penso che ci potrebbe essere uno sforzo più consolidato in una risposta per spiegare meglio la relazione tra il modulo datetime di Python, gli oggetti datetime64 / timedelta64 di numpy e gli oggetti Timestamp / Timedelta di Panda.

La libreria standard datetime di Python

La libreria standard datetime ha quattro oggetti principali

  • tempo - solo tempo, misurato in ore, minuti, secondi e microsecondi
  • data - solo anno, mese e giorno
  • datetime - Tutti i componenti di ora e data
  • timedelta - Una quantità di tempo con unità massima di giorni

Crea questi quattro oggetti

>>> import datetime
>>> datetime.time(hour=4, minute=3, second=10, microsecond=7199)
datetime.time(4, 3, 10, 7199)

>>> datetime.date(year=2017, month=10, day=24)
datetime.date(2017, 10, 24)

>>> datetime.datetime(year=2017, month=10, day=24, hour=4, minute=3, second=10, microsecond=7199)
datetime.datetime(2017, 10, 24, 4, 3, 10, 7199)

>>> datetime.timedelta(days=3, minutes = 55)
datetime.timedelta(3, 3300)

>>> # add timedelta to datetime
>>> datetime.timedelta(days=3, minutes = 55) + \
    datetime.datetime(year=2017, month=10, day=24, hour=4, minute=3, second=10, microsecond=7199)
datetime.datetime(2017, 10, 27, 4, 58, 10, 7199)

Oggetti datetime64 e timedelta64 di NumPy

NumPy non ha oggetti separati di data e ora, solo un singolo oggetto datetime64 per rappresentare un singolo momento nel tempo. L'oggetto datetime del modulo datetime ha una precisione di microsecondi (un milionesimo di secondo). L'oggetto datetime64 di NumPy ti consente di impostare la sua precisione dalle ore fino agli attosecondi (10 ^ -18). Il costruttore è più flessibile e può accettare una varietà di input.

Costruisci gli oggetti datetime64 e timedelta64 di NumPy

Passa un numero intero con una stringa per le unità. Vedi tutte le unità qui . Viene convertito in tante unità dopo l'epoca UNIX: 1 gennaio 1970

>>> np.datetime64(5, 'ns') 
numpy.datetime64('1970-01-01T00:00:00.000000005')

>>> np.datetime64(1508887504, 's')
numpy.datetime64('2017-10-24T23:25:04')

Puoi anche usare le stringhe purché siano nel formato ISO 8601.

>>> np.datetime64('2017-10-24')
numpy.datetime64('2017-10-24')

I Timedeltas hanno una singola unità

>>> np.timedelta64(5, 'D') # 5 days
>>> np.timedelta64(10, 'h') 10 hours

Puoi anche crearli sottraendo due oggetti datetime64

>>> np.datetime64('2017-10-24T05:30:45.67') - np.datetime64('2017-10-22T12:35:40.123')
numpy.timedelta64(147305547,'ms')

Pandas Timestamp e Timedelta offrono molte più funzionalità su NumPy

Un panda Timestamp è un momento nel tempo molto simile a un datetime ma con molte più funzionalità. Puoi costruirli con pd.Timestampo pd.to_datetime.

>>> pd.Timestamp(1239.1238934) #defautls to nanoseconds
Timestamp('1970-01-01 00:00:00.000001239')

>>> pd.Timestamp(1239.1238934, unit='D') # change units
Timestamp('1973-05-24 02:58:24.355200')

>>> pd.Timestamp('2017-10-24 05') # partial strings work
Timestamp('2017-10-24 05:00:00')

pd.to_datetime funziona in modo molto simile (con alcune altre opzioni) e può convertire un elenco di stringhe in timestamp.

>>> pd.to_datetime('2017-10-24 05')
Timestamp('2017-10-24 05:00:00')

>>> pd.to_datetime(['2017-1-1', '2017-1-2'])
DatetimeIndex(['2017-01-01', '2017-01-02'], dtype='datetime64[ns]', freq=None)

Conversione di Python datetime in datetime64 e Timestamp

>>> dt = datetime.datetime(year=2017, month=10, day=24, hour=4, 
                   minute=3, second=10, microsecond=7199)
>>> np.datetime64(dt)
numpy.datetime64('2017-10-24T04:03:10.007199')

>>> pd.Timestamp(dt) # or pd.to_datetime(dt)
Timestamp('2017-10-24 04:03:10.007199')

Conversione numpy datetime64 in datetime e Timestamp

>>> dt64 = np.datetime64('2017-10-24 05:34:20.123456')
>>> unix_epoch = np.datetime64(0, 's')
>>> one_second = np.timedelta64(1, 's')
>>> seconds_since_epoch = (dt64 - unix_epoch) / one_second
>>> seconds_since_epoch
1508823260.123456

>>> datetime.datetime.utcfromtimestamp(seconds_since_epoch)
>>> datetime.datetime(2017, 10, 24, 5, 34, 20, 123456)

Converti in data e ora

>>> pd.Timestamp(dt64)
Timestamp('2017-10-24 05:34:20.123456')

Converti da Timestamp a datetime e datetime64

Questo è abbastanza facile poiché i timestamp dei panda sono molto potenti

>>> ts = pd.Timestamp('2017-10-24 04:24:33.654321')

>>> ts.to_pydatetime()   # Python's datetime
datetime.datetime(2017, 10, 24, 4, 24, 33, 654321)

>>> ts.to_datetime64()
numpy.datetime64('2017-10-24T04:24:33.654321000')

3
È pazzesco quanto sia insensibile il datetime è ancora difficile / hacky ... non c'è davvero modo migliore? Questa è una buona risposta, sto pensando di accettare di spostarlo al livello più alto, devo leggere gli altri più profondamente una volta da un computer.
Andy Hayden,

Cosa c'è di così strano? I timestamp di Panda funzionano bene e sono abbastanza semplici.
Ted Petrou,

2
Numpy a datetime.
Andy Hayden,

1
Penso che questa sia la migliore risposta che abbia mai visto. Proveniente da Excel, VBA, SAS o SQL, Python sembra strano perché non c'è solo "un modo" per lavorare con date / orari. Come per molte cose in Python o R, sembra che si debba scegliere un metodo / modulo / classe preferito e attenersi ad esso.
Sean McCarthy,

Amazing ansewer
gioxc88

29
>>> dt64.tolist()
datetime.datetime(2012, 5, 1, 0, 0)

Per DatetimeIndex, tolistrestituisce un elenco di datetimeoggetti. Per un singolo datetime64oggetto restituisce un singolo datetimeoggetto.


Avrei davvero dovuto provare tutti i metodi :) (Sono scioccato da quanto tempo ero alle prese con questo) Grazie
Andy Hayden

5
@hayden se sai che è un array scalare / 0-d, preferirei usare il .item()che è molto più esplicito (e nessuno può venire in giro e iniziare a discutere che dovrebbe restituire un elenco).
seberg,

1
Temo che questo non funzioni sempre: ad es. dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100'), Che dà un lungo ( 1025222400000000000L) (!)
Andy Hayden,

4
@hayden: il tipo che viene restituito .item()(suggerito da @seberg), .tolist()dipende dalle unità utilizzate da datetime64, ad esempio, Dproduce datetime.date(), us(microsecondi) datetime.datetime(), produce ns(nanosecondi) long. E le unità cambiano in base ai valori di input, ad es. numpy.datetime64('2012-05-01')Usi 'D', numpy.datetime64('2012-05-01T00:00:00.000')usi ms, numpy.datetime64('2012-05-01T00:00:00.000000000')usi ns. Potresti aprire un problema se lo trovi confuso.
jfs,

@AndyHayden Potresti anche semplicemente aggiungere un argomento in più, 'us' o 'ms' per assicurarti che lo stesso formato sia applicato, producendo lo stesso elemento datetime in tolist ()
NM

11

Se si desidera convertire un'intera serie di periodi di dati Panda in normali periodi di tempo Python, è anche possibile utilizzare .to_pydatetime().

pd.date_range('20110101','20110102',freq='H').to_pydatetime()

> [datetime.datetime(2011, 1, 1, 0, 0) datetime.datetime(2011, 1, 1, 1, 0)
   datetime.datetime(2011, 1, 1, 2, 0) datetime.datetime(2011, 1, 1, 3, 0)
   ....

Supporta anche fusi orari:

pd.date_range('20110101','20110102',freq='H').tz_localize('UTC').tz_convert('Australia/Sydney').to_pydatetime()

[ datetime.datetime(2011, 1, 1, 11, 0, tzinfo=<DstTzInfo 'Australia/Sydney' EST+11:00:00 DST>)
 datetime.datetime(2011, 1, 1, 12, 0, tzinfo=<DstTzInfo 'Australia/Sydney' EST+11:00:00 DST>)
....

NOTA : se si utilizza una serie Pandas non è possibile chiamare to_pydatetime()l'intera serie. Dovrai chiamare .to_pydatetime()ogni singolo datetime64 usando una comprensione dell'elenco o qualcosa di simile:

datetimes = [val.to_pydatetime() for val in df.problem_datetime_column]

10

Un'opzione è usare str, quindi to_datetime(o simili):

In [11]: str(dt64)
Out[11]: '2012-05-01T01:00:00.000000+0100'

In [12]: pd.to_datetime(str(dt64))
Out[12]: datetime.datetime(2012, 5, 1, 1, 0, tzinfo=tzoffset(None, 3600))

Nota: non è uguale a dtperché è diventato "offset-aware" :

In [13]: pd.to_datetime(str(dt64)).replace(tzinfo=None)
Out[13]: datetime.datetime(2012, 5, 1, 1, 0)

Questo sembra inelegante.

.

Aggiornamento: questo può far fronte al "cattivo esempio":

In [21]: dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100')

In [22]: pd.to_datetime(str(dt64)).replace(tzinfo=None)
Out[22]: datetime.datetime(2002, 6, 28, 1, 0)

Grazie Andy per aver condiviso questo suggerimento. Per qualche motivo non riesco a farlo funzionare, come discuto qui: stackoverflow.com/questions/22825349/…
Amelio Vazquez-Reina,

@ user815423426 questa non è mai stata una soluzione molto solida, suppongo che tu possa passare un formato al costruttore del datetime per lavorare più in generale. Non molto pandastico però!
Andy Hayden,

8

Questo post è attivo da 4 anni e ho ancora lottato con questo problema di conversione, quindi il problema è ancora attivo nel 2017 in un certo senso. Sono rimasto un po 'scioccato dal fatto che la documentazione insensibile non offra prontamente un semplice algoritmo di conversione, ma questa è un'altra storia.

Mi sono imbattuto in un altro modo di fare la conversione che coinvolge solo i moduli numpye datetimenon richiede l'importazione di panda, che mi sembra molto codice da importare per una conversione così semplice. Ho notato che datetime64.astype(datetime.datetime)restituirà un datetime.datetimeoggetto se l'originale si datetime64trova in unità di micro secondi mentre altre unità restituiscono un timestamp intero. Uso il modulo xarrayper l'I / O dei dati dai file Netcdf che utilizza le datetime64unità in nanosecondi, facendo fallire la conversione a meno che non si converta prima in unità di micro-secondi. Ecco il codice di conversione di esempio,

import numpy as np
import datetime

def convert_datetime64_to_datetime( usert: np.datetime64 )->datetime.datetime:
    t = np.datetime64( usert, 'us').astype(datetime.datetime)
return t

È testato solo sulla mia macchina, che è Python 3.6 con una recente distribuzione Anaconda 2017. Ho esaminato solo la conversione scalare e non ho verificato le conversioni basate su array, anche se immagino che andrà bene. Né ho esaminato il codice sorgente datetime64 intorpidito per vedere se l'operazione ha senso o no.


Questo è fantastico Grazie di averlo fatto.
Yu Chen,

Roba buona. Grazie.
misantroop,

1

Sono tornato a questa risposta più volte di quante ne possa contare, quindi ho deciso di mettere insieme una piccola classe veloce, che converte un datetime64valore Numpy in valore Python datetime. Spero che aiuti gli altri là fuori.

from datetime import datetime
import pandas as pd

class NumpyConverter(object):
    @classmethod
    def to_datetime(cls, dt64, tzinfo=None):
        """
        Converts a Numpy datetime64 to a Python datetime.
        :param dt64: A Numpy datetime64 variable
        :type dt64: numpy.datetime64
        :param tzinfo: The timezone the date / time value is in
        :type tzinfo: pytz.timezone
        :return: A Python datetime variable
        :rtype: datetime
        """
        ts = pd.to_datetime(dt64)
        if tzinfo is not None:
            return datetime(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, tzinfo=tzinfo)
        return datetime(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second)

Lo terrò nella mia borsa degli attrezzi, qualcosa mi dice che ne avrò ancora bisogno.


2
Potresti semplicemente farets.to_pydatetime()
Ted Petrou il

0
import numpy as np
import pandas as pd 

def np64toDate(np64):
    return pd.to_datetime(str(np64)).replace(tzinfo=None).to_datetime()

usa questa funzione per ottenere l'oggetto datetime nativo di Pythons


Ho ricevuto un errore dicendoreplace() got an unexpected keyword argument 'tzinfo'
ogogmad,

quale versione di Panda usi? Ho la versione 0.18.1 (pip show panda)
Crystal,

come te. . .
Ogogmad,

Non lo so allora, ma funziona per me come il fascino. pix.toile-libre.org/upload/original/1475645621.png
Crystal,

0

Alcune soluzioni funzionano bene per me, ma numpy deprecherà alcuni parametri. La soluzione che funziona meglio per me è leggere la data come un petime datetime ed espellere esplicitamente l'anno, il mese e il giorno di un oggetto panda. Il codice seguente funziona per la situazione più comune.

def format_dates(dates):
    dt = pd.to_datetime(dates)
    try: return [datetime.date(x.year, x.month, x.day) for x in dt]    
    except TypeError: return datetime.date(dt.year, dt.month, dt.day)

-1

in effetti, tutti questi tipi di data e ora possono essere difficili e potenzialmente problematici (devono tenere traccia delle informazioni sul fuso orario). ecco cosa ho fatto, anche se ammetto che sono preoccupato che almeno in parte sia "non progettato". inoltre, questo può essere reso un po 'più compatto, se necessario. che inizia con un numpy.datetime64 dt_a:

dt_a

numpy.datetime64 ( '2015-04-24T23: 11: 26,270000-0.700')

dt_a1 = dt_a.tolist () # produce un oggetto datetime in UTC, ma senza tzinfo

dt_a1

datetime.datetime (2015, 4, 25, 6, 11, 26, 270000)

# now, make your "aware" datetime:

dt_a2 = datetime.datetime (* list (dt_a1.timetuple () [: 6]) + [dt_a1.microsecond], tzinfo = pytz.timezone ('UTC'))

... e, naturalmente, può essere compresso in una riga secondo necessità.


docs.scipy.org/doc/numpy/reference/… per le modifiche nella gestione del fuso orario.
hpaulj,

Si prega editdi conformarsi con la corretta: formattazione del codice, formattazione del preventivo e formattazione del testo. Inoltre, si prega di aderire alla corretta capitalizzazione, grammatica e controllo di errori di battitura, secondo le linee guida SO - vedere: Come
inviare
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.