python - with - to datetime pandas format
Conversión entre datetime, Timestamp y datetime64 (12)
Algunas soluciones funcionan bien para mí, pero numpy eliminará algunos parámetros. La solución que me funciona mejor es leer la fecha como fecha y hora de pandas y excretar explícitamente el año, mes y día de un objeto pandas. El siguiente código funciona para la situación más común.
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)
¿Cómo convierto un objeto numpy.datetime64
a datetime.datetime
(o Timestamp
)?
En el siguiente código, creo un objeto datetime, timestamp y 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: es fácil obtener la fecha y hora de la marca de tiempo:
In [10]: ts.to_datetime()
Out[10]: datetime.datetime(2012, 5, 1, 0, 0)
Pero, ¿cómo extraemos datetime
o Timestamp
de un numpy.datetime64
( dt64
)?
.
Actualización: un ejemplo un tanto desagradable en mi conjunto de datos (quizás el ejemplo motivador) parece ser:
dt64 = numpy.datetime64(''2002-06-28T01:00:00.000000000+0100'')
que debería ser datetime.datetime(2002, 6, 28, 1, 0)
y no un largo (!) ( 1025222400000000000L
) ...
Bienvenido al infierno.
Solo puedes pasar un objeto datetime64 a pandas.Timestamp
:
In [16]: Timestamp(numpy.datetime64(''2012-05-01T01:00:00.000000''))
Out[16]: <Timestamp: 2012-05-01 01:00:00>
Noté que esto no funciona bien en NumPy 1.6.1:
numpy.datetime64(''2012-05-01T01:00:00.000000+0100'')
Además, se puede usar pandas.to_datetime
(esto está fuera de la versión dev, no se ha verificado 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))
Creo que podría haber un esfuerzo más consolidado en una respuesta para explicar mejor la relación entre el módulo datetime de Python, datetime64 / timedelta64 de numpy y los objetos Timestamp / Timedelta de pandas.
La biblioteca estándar de datetime de Python
La biblioteca estándar de datetime tiene cuatro objetos principales
- tiempo - solo tiempo, medido en horas, minutos, segundos y microsegundos
- fecha - solo año, mes y día
- datetime - Todos los componentes de hora y fecha
- timedelta - Una cantidad de tiempo con una unidad máxima de días
Crea estos cuatro objetos.
>>> 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)
Objetos datetime64 y timedelta64 de NumPy
NumPy no tiene objetos de fecha y hora separados, solo un objeto datetime64 para representar un momento en el tiempo. El objeto datetime del módulo datetime tiene una precisión de microsegundos (una millonésima de segundo). El objeto datetime64 de NumPy le permite establecer su precisión desde horas hasta attosegundos (10 ^ -18). Su constructor es más flexible y puede tomar una variedad de entradas.
Construye los objetos datetime64 y timedelta64 de NumPy
Pase un entero con una cadena para las unidades. Ver todas las unidades aquí . Se convierte a tantas unidades después de la época de UNIX: 1 de enero de 1970
>>> np.datetime64(5, ''ns'')
numpy.datetime64(''1970-01-01T00:00:00.000000005'')
>>> np.datetime64(1508887504, ''s'')
numpy.datetime64(''2017-10-24T23:25:04'')
También puede utilizar cadenas siempre que estén en formato ISO 8601.
>>> np.datetime64(''2017-10-24'')
numpy.datetime64(''2017-10-24'')
Timedeltas tiene una sola unidad
>>> np.timedelta64(5, ''D'') # 5 days
>>> np.timedelta64(10, ''h'') 10 hours
También puede crearlos restando dos objetos datetime64
>>> np.datetime64(''2017-10-24T05:30:45.67'') - np.datetime64(''2017-10-22T12:35:40.123'')
numpy.timedelta64(147305547,''ms'')
Pandas Timestamp y Timedelta construyen mucha más funcionalidad sobre NumPy
Una marca de tiempo de pandas es un momento en el tiempo muy similar a una fecha y hora pero con mucha más funcionalidad. Puedes construirlos con pd.Timestamp
o 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
funciona de manera muy similar (con algunas opciones más) y puede convertir una lista de cadenas en marcas de tiempo.
>>> 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)
Convertir datetime de Python en datetime64 y marca de tiempo
>>> 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'')
Convertir numpy datetime64 a datetime y 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)
Convertir a marca de tiempo
>>> pd.Timestamp(dt64)
Timestamp(''2017-10-24 05:34:20.123456'')
Convertir de marca de tiempo a datetime y datetime64
Esto es bastante fácil ya que las marcas de tiempo de los pandas son muy poderosas.
>>> 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'')
Este post ha estado activo durante 4 años y todavía tuve problemas con este problema de conversión, por lo que el problema sigue activo en 2017 en cierto sentido. Me sorprendió un poco que la documentación numpy no ofrezca fácilmente un algoritmo de conversión simple, pero esa es otra historia.
Me he encontrado con otra forma de hacer la conversión que solo involucra módulos numpy
y datetime
, no requiere la importación de pandas, lo que me parece una gran cantidad de código para una conversión tan simple. Noté que datetime64.astype(datetime.datetime)
devolverá un objeto datetime.datetime
si el datetime64
original está en unidades de microsegundos mientras que otras unidades devuelven una marca de tiempo de entero. Utilizo el módulo xarray
para la E / S de datos de archivos Netcdf que usa el datetime64
en unidades de nanosegundos que hacen que la conversión falle a menos que primero convierta a unidades de microsegundos. Aquí está el código de conversión de ejemplo,
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
Solo se probó en mi máquina, que es Python 3.6 con una distribución reciente de Anaconda 2017. Solo he analizado la conversión escalar y no he comprobado las conversiones basadas en matrices, aunque supongo que será bueno. Tampoco he mirado el código fuente de datpy 64 numpy para ver si la operación tiene sentido o no.
Para convertir numpy.datetime64
en un objeto datetime que representa el tiempo en UTC en 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''
El ejemplo anterior asume que np.datetime64
interpreta un objeto de fecha y hora ingenuo como tiempo en UTC.
Para convertir datetime a np.datetime64 y viceversa ( numpy-1.6
):
>>> np.datetime64(datetime.utcnow()).astype(datetime)
datetime.datetime(2012, 12, 4, 13, 34, 52, 827542)
Funciona tanto en un solo objeto np.datetime64 como en una matriz numpy de np.datetime64.
Piense en np.datetime64 de la misma manera que lo haría en np.int8, np.int16, etc. y aplique los mismos métodos para convertir entre objetos de Python, como int, datetime y los objetos numpy correspondientes.
Tu "ejemplo desagradable" funciona correctamente:
>>> 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
Puedo reproducir el valor long
en numpy-1.8.0
instalado como:
pip install git+https://github.com/numpy/numpy.git#egg=numpy-dev
El mismo ejemplo:
>>> 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''
Devuelve long
porque para numpy.datetime64
tipo .astype(datetime)
es equivalente a .astype(object)
que devuelve el entero Python ( long
) en numpy-1.8
.
Para obtener el objeto datetime usted podría:
>>> 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)
Para obtener datetime64 que usa segundos directamente:
>>> 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)
Los documentos numpy dicen que la API datetime es experimental y puede cambiar en futuras versiones numpy.
Puedes usar el constructor pd.Timestamp. El siguiente diagrama puede ser útil para esto y otras preguntas relacionadas.
Regresé a esta respuesta más veces de las que puedo contar, así que decidí juntar una pequeña clase rápida, que convierte un valor de Numpy datetime64
valor de Python datetime
. Espero que ayude a otros por ahí.
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)
Voy a mantener esto en mi bolsa de herramientas, algo me dice que lo necesitaré de nuevo.
Si desea convertir una serie completa de pandas de .to_pydatetime()
regulares de Python, también puede usar .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)
....
También soporta zonas horarias:
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>)
....
Una opción es usar str
, y luego to_datetime
(o similar):
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: no es igual a dt
porque se ha vuelto "offset-aware" :
In [13]: pd.to_datetime(str(dt64)).replace(tzinfo=None)
Out[13]: datetime.datetime(2012, 5, 1, 1, 0)
Esto parece poco elegante.
.
Actualización: esto puede tratar con el "ejemplo desagradable":
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)
de hecho, todos estos tipos de fecha y hora pueden ser difíciles y potencialmente problemáticos (deben mantener un seguimiento cuidadoso de la información de la zona horaria). esto es lo que he hecho, aunque admito que me preocupa que al menos parte de esto no sea "por diseño". Además, esto se puede hacer un poco más compacto según sea necesario. comenzando con un numpy.datetime64 dt_a:
dt_a
numpy.datetime64 (''2015-04-24T23: 11: 26.270000-0700'')
dt_a1 = dt_a.tolist () # produce un objeto datetime en UTC, pero sin 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''))
... y por supuesto, eso se puede comprimir en una línea según sea necesario.
>>> dt64.tolist()
datetime.datetime(2012, 5, 1, 0, 0)
Para DatetimeIndex
, la lista de tolist
devuelve una lista de objetos de datetime
. Para un solo objeto datetime64
devuelve un solo objeto datetime
.
import numpy as np
import pandas as pd
def np64toDate(np64):
return pd.to_datetime(str(np64)).replace(tzinfo=None).to_datetime()
Utilice esta función para obtener objetos nativos de fecha y hora de Pythons.