Convertendo entre datetime, timestamp e datetime64

290

Como faço para converter um numpy.datetime64objeto em um datetime.datetime(ou Timestamp)?

No código a seguir, crio objetos 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: é fácil obter a data e hora do carimbo de data / hora:

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

Mas como extraímos o datetimeou Timestampde um numpy.datetime64( dt64)?

.

Atualização: um exemplo um tanto desagradável no meu conjunto de dados (talvez o exemplo motivador) parece ser:

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

que deveria ser datetime.datetime(2002, 6, 28, 1, 0), e não demorou muito (!) ( 1025222400000000000L) ...

Andy Hayden
fonte
2
você provavelmente deve aceitar a resposta de @Wes McKinney que é muito mais curto e deve funcionar em recentes numpy, pandasversões.
JFS
@JFSebastian Hmmm, isso significa que a resposta é "não mude de np.datetime para datetime" ... basta usar pd.Timestamp (como é uma subclasse de datetime de qualquer maneira), ou se você realmente deve usá-lo pd.Timestamp(dt64).to_datetime(). Ainda estou um pouco insatisfeito com isso, mas certamente o Wes 'é menos específico para o meu antigo problema (e, portanto, melhor para o mundo)! Obrigado novamente por reservar um tempo para responder. :)
Andy Hayden
A sua pergunta diz "ou Timestamp" e Timestampé um datetime(uma subclasse de) de qualquer maneira :)
jfs
3
Para aqueles que chegam a esta pergunta em 2017 ou mais, veja minha resposta abaixo para obter um tutorial detalhado de datetime, datetime64 e Timestamps: stackoverflow.com/a/46921593/3707607
Ted Petrou

Respostas:

132

Para converter numpy.datetime64em objeto de data e hora que representa a hora no UTC em 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'

O exemplo acima pressupõe que um objeto de data e hora ingênuo seja interpretado np.datetime64como hora no UTC.


Para converter datetime em np.datetime64 e back ( numpy-1.6):

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

Ele funciona tanto em um único objeto np.datetime64 quanto em uma matriz numpy de np.datetime64.

Pense em np.datetime64 da mesma maneira que faria com np.int8, np.int16, etc e aplique os mesmos métodos para converter entre objetos Python, como int, datetime e objetos numpy correspondentes.

O seu "exemplo desagradável" funciona corretamente:

>>> 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

Eu posso reproduzir o longvalor numpy-1.8.0instalado como:

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

O mesmo exemplo:

>>> 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'

Ele retorna longporque for numpy.datetime64type .astype(datetime)é equivalente ao .astype(object)que retorna Python integer ( long) on numpy-1.8.

Para obter o objeto datetime, você pode:

>>> 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 obter datetime64 que usa segundos diretamente:

>>> 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)

Os documentos numpy dizem que a API datetime é experimental e pode mudar em versões numpy futuras.

jfs
fonte
1
Receio que isso nem sempre funcione: por exemplo dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100'), o que dá um longo ( 1025222400000000000L) (!)
Andy Hayden
@ Hayden: tente type(dt64). dt64.astype(datetime) == datetime.utcfromtimestamp(dt64.astype(int)*1e-6)
JFS
@JFSebastian type(dt64)é numpy.datetime64e dt64.astype(datetime)é o mesmo longo int ...: s
Andy Hayden
@ Hayden: Qual é a sua versão numpy? Meu: numpy.__version__->'1.6.1'
jfs 04/12/12
Versão 1.8.0 (em python 2.7.3), se funcionar, sugerirá que é um bug no meu sistema!
Andy Hayden
212

Você pode apenas usar o construtor pd.Timestamp. O diagrama a seguir pode ser útil para esta e outras questões relacionadas.

Conversões entre representações de tempo

Quant
fonte
2
Agradável!!! (Vale a pena mencionar que a situação melhorou desde que eu escrevi esta pergunta, muito trabalho tem sido feito aqui :))
Andy Hayden
107
Só de olhar para este diagrama, há algo fundamentalmente errado em todo esse tempo.
ouriço demente
4
É muito confuso que pd.to_datetime produza um TimeStamp se for fornecido o número de ms ou ns, mas produzirá um datetime.datetime se for dado um datetime.datetime ou um np.datetime64 se for dado um np.datetime64 ... Por que alguém acha que isso é razoável?
Mr.WorshipMe
7
@ Mr.WorshipMe Este diagrama precisa ser atualizado. pd.to_datetimeconverte tudo para pd.Timestamp. Um pd.Timestampobjeto tem o método to_pydatetimepara reverter para um datetime.datetimeobjeto e um to_datetime64método para o qual converter np.datetime64.
Ted Petrou
2
Como posso obter uma resolução mais alta dessa foto?
precisa saber é o seguinte
137

Bem-vindo ao inferno.

Você pode simplesmente passar um objeto datetime64 para pandas.Timestamp:

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

Notei que isso não funciona corretamente no NumPy 1.6.1:

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

Além disso, pandas.to_datetimepode ser usado (isso está fora da versão dev, não verifique a 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))
Wes McKinney
fonte
5
Você deve mencionar que issubclass(pd.Timestamp, datetime)é True. E a Timestampprópria classe tem to_datetime()método.
precisa saber é
7
pd.to_datetime('2012-05-01T01:00:00.000000+0100')retorna Timestamp('2012-05-01 00:00:00')pelo menos em pandas 0.17.1.
Anton Protopopov 21/01
96

Eu acho que poderia haver um esforço mais consolidado em uma resposta para explicar melhor a relação entre o módulo datetime do Python, o datetime64 / timedelta64 do numpy e os objetos Timestamp / Timedelta do pandas.

A biblioteca padrão de data e hora do Python

A biblioteca padrão de data e hora possui quatro objetos principais

  • time - somente time, medido em horas, minutos, segundos e microssegundos
  • data - apenas ano, mês e dia
  • datetime - Todos os componentes de data e hora
  • timedelta - um período de tempo com unidade máxima de dias

Crie esses quatro 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 e timedelta64 de NumPy

O NumPy não possui objetos de data e hora separados, apenas um único objeto datetime64 para representar um único momento no tempo. O objeto datetime do módulo datetime possui precisão de microssegundos (um milionésimo de segundo). O objeto datetime64 do NumPy permite que você defina sua precisão de horas até attossegundos (10 ^ -18). Seu construtor é mais flexível e pode receber uma variedade de entradas.

Construir objetos datetime64 e timedelta64 de NumPy

Passe um número inteiro com uma sequência para as unidades. Veja todas as unidades aqui . Ele é convertido em muitas unidades após a época do UNIX: 1º de janeiro 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')

Você também pode usar cadeias de caracteres desde que estejam no formato ISO 8601.

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

Timedeltas têm uma única unidade

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

Também pode criá-los subtraindo dois objetos datetime64

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

O Pandas Timestamp e Timedelta criam muito mais funcionalidades sobre o NumPy

Um carimbo de data / hora do panda é um momento muito semelhante a um datetime, mas com muito mais funcionalidade. Você pode construí-los com pd.Timestampou 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 maneira muito semelhante (com mais algumas opções) e pode converter uma lista de strings em timestamps.

>>> 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)

Convertendo datetime do Python em 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')

Convertendo numpy datetime64 em 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)

Converter em carimbo de data / hora

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

Converter de carimbo de data e hora em datetime e datetime64

Isso é muito fácil, pois os timestamps dos pandas são muito poderosos

>>> 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')
Ted Petrou
fonte
3
É uma loucura o quão entorpecida a data e hora ainda é difícil / hacky ... não existe realmente uma maneira melhor? Esta é uma boa resposta, estou pensando em aceitar movê-la para o nível superior. Tenho que ler os outros mais profundamente uma vez por um computador.
Andy Hayden
O que há de tão peculiar nisso? Os carimbos de data e hora do Pandas funcionam bem e são bastante simples.
Ted Petrou
2
Numpy para data e hora.
Andy Hayden
1
Eu acho que essa é a melhor resposta que eu já vi. Vindo do Excel, VBA, SAS ou SQL, o Python parece estranho porque não há apenas "uma maneira" de trabalhar com datas / horas. Como em muitas coisas em Python ou R, parece que é preciso escolher um método / módulo / classe favorito e ficar com ele.
Sean McCarthy
Ansewer incrível
gioxc88
29
>>> dt64.tolist()
datetime.datetime(2012, 5, 1, 0, 0)

Para DatetimeIndex, o tolistretorna uma lista de datetimeobjetos. Para um único datetime64objeto, ele retorna um único datetimeobjeto.

eumiro
fonte
Eu realmente deveria ter tentado todos os métodos :) (Eu estou chocado com quanto tempo eu estava lutando com este) Graças
Andy Hayden
5
@ Hayden, se você sabe que é uma matriz escalar / 0-d, eu prefiro usar o .item()que é muito mais explícito (e ninguém pode vir por aí e começar a argumentar que deve retornar uma lista).
Seberg
1
Receio que isso nem sempre funcione: por exemplo dt64 = numpy.datetime64('2002-06-28T01:00:00.000000000+0100'), o que dá um longo ( 1025222400000000000L) (!)
Andy Hayden
4
@hayden: o tipo retornado por .item()(sugerido por @seberg) .tolist()depende de quais unidades o datetime64 usa, por exemplo, Dproduz datetime.date(), us(microssegundos) produz datetime.datetime(), ns(nanossegundos) produz long. E as unidades mudam dependendo dos valores de entrada, por exemplo, numpy.datetime64('2012-05-01')usos 'D', numpy.datetime64('2012-05-01T00:00:00.000')usos ms, numpy.datetime64('2012-05-01T00:00:00.000000000')usos ns. Você pode abrir um problema se achar confuso.
JFS
@AndyHayden Você também pode adicionar um argumento extra, 'us' ou 'ms' para garantir que o mesmo formato seja aplicado, resultando no mesmo elemento de data e hora sendo produzido em tolist ()
NM
11

Se você deseja converter uma série inteira de horários do pandas em horários regulares do python, também pode 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)
   ....

Ele também suporta fusos horários:

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 você estiver operando em uma série Pandas, não poderá acessar to_pydatetime()a série inteira. Você precisará chamar .to_pydatetime()cada datetime64 individual usando uma compreensão de lista ou algo semelhante:

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

Uma opção é usar stre, em seguida to_datetime(ou 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: não é igual a dtporque se tornou "sensível a deslocamento" :

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

Isso parece deselegante.

.

Atualização: isso pode lidar com o "exemplo desagradável":

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)
Andy Hayden
fonte
Obrigado Andy por compartilhar esta dica. Por alguma razão eu sou incapaz de fazê-lo funcionar, porque eu discuto aqui: stackoverflow.com/questions/22825349/...
Amelio Vazquez-Reina
@ user815423426 essa nunca foi uma solução muito robusta, acho que você pode passar um formato para o construtor datetime para trabalhar de maneira mais geral. Não é muito pandástico!
Andy Hayden
8

Esta postagem existe há 4 anos e eu ainda tenho problemas com esse problema de conversão - portanto, o problema ainda está ativo em 2017, em algum sentido. Fiquei um pouco chocado que a documentação numpy não oferece prontamente um algoritmo de conversão simples, mas isso é outra história.

Me deparei com outra maneira de fazer a conversão que envolve apenas módulos numpye datetime, não é necessário importar pandas, o que me parece ser muito código para importar para uma conversão tão simples. Notei que datetime64.astype(datetime.datetime)retornará um datetime.datetimeobjeto se o original datetime64estiver em unidades de microssegundo, enquanto outras unidades retornam um carimbo de data / hora inteiro. Eu uso o módulo xarraypara E / S de dados de arquivos Netcdf, que usa as datetime64unidades em nanossegundos que causam falha na conversão, a menos que você primeiro converta em unidades de microssegundo. Aqui está o código de conversão de exemplo,

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

Ele foi testado apenas na minha máquina, que é o Python 3.6 com uma recente distribuição Anaconda de 2017. Eu olhei apenas para a conversão escalar e não verifiquei as conversões baseadas em matriz, embora eu ache que será bom. Também não observei o código fonte numpy datetime64 para ver se a operação faz sentido ou não.

ndl303
fonte
Isso é ótimo. Obrigado por fazer isso.
Yu Chen
Coisa boa. Obrigado.
misantroop
1

Voltei a esta resposta mais vezes do que posso contar, então decidi criar uma turma rápida, que converte um datetime64valor Numpy em valor Python datetime. Espero que ajude outras pessoas por aí.

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)

Vou guardar isso na minha mala de ferramentas, algo me diz que precisarei novamente.

MikeyE
fonte
2
Você poderia simplesmente fazerts.to_pydatetime()
Ted Petrou
0
import numpy as np
import pandas as pd 

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

use esta função para obter pythons objeto datetime nativo

Cristal
fonte
Eu tenho um erro dizendoreplace() got an unexpected keyword argument 'tzinfo'
ogogmad 4/16
qual versão pandas você usa tenho Versão: 0.18.1 (pip mostram pandas)
Cristal
o mesmo que você. . .
ogogmad
Eu não sei então, mas funciona para mim como charme. pix.toile-libre.org/upload/original/1475645621.png
Cristal
0

Algumas soluções funcionam bem para mim, mas o numpy depreciará alguns parâmetros. A solução que funciona melhor para mim é ler a data como data e hora do panda e excretar explicitamente o ano, mês e dia de um objeto do panda. O código a seguir funciona para a situação mais comum.

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)
João Gabriel John
fonte
-1

de fato, todos esses tipos de data e hora podem ser difíceis e potencialmente problemáticos (devem acompanhar cuidadosamente as informações do fuso horário). Aqui está o que eu fiz, embora eu admita que estou preocupado que pelo menos parte dela seja "não por design". Além disso, isso pode ser um pouco mais compacto, conforme necessário. começando com um numpy.datetime64 dt_a:

dt_a

numpy.datetime64 ('2015-04-24T23: 11: 26.270000-0700')

dt_a1 = dt_a.tolist () # gera um objeto datetime no UTC, mas sem 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, é claro, isso pode ser compactado em uma linha, conforme necessário.

yoder
fonte
docs.scipy.org/doc/numpy/reference/… para alterações no manuseio do fuso horário.
Hpaulj # 30/17
Por favor, editpara estar em conformidade com: formatação de código, formatação de citação e formatação de texto. Além disso, adote a capitalização, gramática e verificação de erros de digitação adequados, de acordo com as diretrizes da SO - consulte: Como postar e codificar amostras
SherylHohman