Como alterar o formato de data e hora no pandas

109

Meu dataframe tem uma DOBcoluna (formato de exemplo 1/1/2016) que, por padrão, é convertida para 'objeto' do tipo pandas dtype:DOB object

Convertendo isso para formato de data com df['DOB'] = pd.to_datetime(df['DOB']), a data é convertido em: 2016-01-26e sua dtypeé: DOB datetime64[ns].

Agora, quero converter esse formato de data para 01/26/2016ou em qualquer outro formato de data geral. Como eu faço isso?

Qualquer que seja o método que tente, sempre mostra a data no 2016-01-26formato.

yome
fonte
Você está procurando uma solução que funcione apenas no notebook Jupyter? (nesse caso, use um 'estilizador' por coluna) ou funciona no console Python simples e no iPython?
smci

Respostas:

208

Você pode usar dt.strftimese precisar converterdatetime para outros formatos (mas observe que então dtypeda coluna será object( string)):

import pandas as pd

df = pd.DataFrame({'DOB': {0: '26/1/2016', 1: '26/1/2016'}})
print (df)
         DOB
0  26/1/2016 
1  26/1/2016

df['DOB'] = pd.to_datetime(df.DOB)
print (df)
         DOB
0 2016-01-26
1 2016-01-26

df['DOB1'] = df['DOB'].dt.strftime('%m/%d/%Y')
print (df)
         DOB        DOB1
0 2016-01-26  01/26/2016
1 2016-01-26  01/26/2016
jezrael
fonte
32
'strftime' converte a coluna datetime em unicode para aplicar a operação em DOB1, novamente temos que convertê-la em datetime. Não existe outra forma de formatação sem perder o data_type?
M.Zaman
@jezrael, existe alguma solução melhor que retém também o tipo de dados e não retorna as datas para uma coluna de objeto? O problema é que se tentar convertê-lo após a linha 'df [' DOB1 '] = df [' DOB ']. Dt.strftime ('% m /% d /% Y ')', conforme sugerido na solução acima, as datas voltam ao formato original.
Pária de
haha, então como posso fazer isso se eu quiser usar essa coluna para uma .mergecoluna datetime de outro dataframe? Faz algum sentido converter a outra coluna datetime em uma coluna de objeto para fazer o .merge?
Pária de
Sim, aparentemente eu concordo, mas por "Não existe :(" você me disse que não consigo converter a coluna para datetime após alterar seu formato sem perder seu novo formato. Então?
Proibido
Ok, pelo que eu entendi, .mergeisso ainda pode ser feito corretamente se ambas as colunas forem colunas de data e hora, mesmo que não tenham exatamente o mesmo formato. Isto está certo?
Pária em
21

Mudar o formato, mas não mudar o tipo:

df['date'] = pd.to_datetime(df["date"].dt.strftime('%Y-%m'))
Yanni Cao
fonte
lembre-se de que df ["data"] deve ser datetime64 antes de você fazer isso
adhg
4
Não! Suponha que o valor original de algum item da datecoluna seja “ 26 de novembro de 2019”. strftime()significa "string do tempo" , então df["date"].dt.strftime('%Y-%m')será uma string "2019-11" para esse item. Então, pd.to_datetime()irá converter esta string de volta para o datetime64formato, mas agora como “ 1 de novembro de 2019”! Portanto, o resultado será: Nenhuma mudança de formato, mas a mudança do próprio valor de data!
MarianD
2
@MarianD: todos os seus comentários sobre as respostas individuais são úteis, mas você pode resumi-los em uma lista de "Armadilhas / Não faça isso" no final da sua resposta? Além disso, você precisa declarar claramente qual é o problema com cada um deles: se qualquer uma das datas de entrada não estiver no formato esperado, elas correrão o risco de gerar exceções ou destruirão a data. Simplesmente escrevendo "Não!" em todos os lugares não transmite isso.
smci
8

O código abaixo funcionou para mim em vez do anterior - experimente!

df['DOB']=pd.to_datetime(df['DOB'].astype(str), format='%m/%d/%Y')
rishi jain
fonte
2
Não! Seu format='%m/%d/%Y'parâmetro é para analisar uma string, ou seja, você deve fornecer a string nesse formato (por exemplo "5/13/2019"). Nada mais, nenhuma mudança de formato. Ele ainda será exibido como 2019-05-13- ou gerará uma exceção, se df['DOB'].astype(str)contiver item (ns) que não estejam em tal formato, por exemplo, em um formato "2019-05-13".
MarianD
4

Em comparação com a primeira resposta, recomendarei usar dt.strftime () primeiro, depois pd.to_datetime (). Dessa forma, ainda resultará no tipo de dados datetime.

Por exemplo,

import pandas as pd

df = pd.DataFrame({'DOB': {0: '26/1/2016 ', 1: '26/1/2016 '})
print(df.dtypes)

df['DOB1'] = df['DOB'].dt.strftime('%m/%d/%Y')
print(df.dtypes)

df['DOB1'] = pd.to_datetime(df['DOB1'])
print(df.dtypes)
usuário3512680
fonte
2
Isso não funciona, pelo menos no meu caso. Especificamente, a coluna é convertida para o tipo de dados datetime, mas também os valores são convertidos para o formato original!
Pária em
Não! Erro de sintaxe (chave faltando), na minha versão do Pandas (0.25.1) outro erro de sintaxe (dt.strftime () - só pode usar acessador .dt com valores datetimelike) - você depende do tipo de dados inerente, mas em diferentes versões de Pandas, os tipos de dados inerentes podem ser diferentes), e uma lógica estranha - por que converter data e hora em string e depois voltar em data e hora ? Veja meu comentário sobre a resposta de rishi jain.
MarianD
2

Existe uma diferença entre

  • o conteúdo de uma célula de dataframe (um valor binário) e
  • sua apresentação (exibindo-o) para nós, humanos.

Portanto, a questão é: como chegar à apresentação adequada dos meus dados sem alterar os próprios dados / tipos de dados?

Aqui está a resposta:

  • Se você usar o notebook Jupyter para exibir seu dataframe, ou
  • se você deseja obter uma apresentação na forma de um arquivo HTML (mesmo com muitos supérfluos ide classatributos preparados para um estilo CSS adicional - você pode ou não usá-los),

usar estilo .O estilo não altera os dados / tipos de dados das colunas do seu dataframe.

Agora vou mostrar como fazer isso no bloco de notas Jupyter - para uma apresentação na forma de arquivo HTML, veja a nota no final da pergunta.

Suponho que sua coluna DOB já tenha o tipodatetime64 (você mostrou que sabe como chegar). Eu preparei um dataframe simples (com apenas uma coluna) para mostrar alguns estilos básicos:

  • Sem estilo:

       df
          DOB
0  2019-07-03
1  2019-08-03
2  2019-09-03
3  2019-10-03
  • Definindo como mm/dd/yyyy:

       df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
          DOB
0  07/03/2019
1  08/03/2019
2  09/03/2019
3  10/03/2019
  • Definindo como dd-mm-yyyy:

       df.style.format({"DOB": lambda t: t.strftime("%d-%m-%Y")}) 
          DOB
0  03-07-2019
1  03-08-2019
2  03-09-2019
3  03-10-2019

Seja cuidadoso!
O objeto de retorno NÃO é um dataframe - é um objeto da classe Styler, portanto , não o atribua de volta a df:

Não faça isso:

df = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})    # Don´t do this!

(Cada dataframe tem seu objeto Styler acessível por sua .stylepropriedade, e mudamos esse df.styleobjeto, não o próprio dataframe.)


Perguntas e respostas:

  • P: Por que seu objeto Styler (ou uma expressão que o retorna) usado como o último comando em uma célula do bloco de notas Jupyter exibe sua tabela (estilizada) e não o próprio objeto Styler?

  • R: Porque cada objeto Styler tem um método de retorno de chamada ._repr_html_()que retorna um código HTML para renderizar seu dataframe (como uma boa tabela HTML).

    O Jupyter Notebook IDE chama esse método automaticamente para renderizar objetos que o possuem.


Nota:

Você não precisa do notebook Jupyter para estilizar (ou seja, para gerar um quadro de dados sem alterar seus tipos de dados / dados ).

Um objeto Styler também tem um método render(), se você quiser obter uma string com o código HTML (por exemplo, para publicar seu dataframe formatado na Web ou simplesmente apresentar sua tabela no formato HTML):

df_styler = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
HTML_string = df_styler.render()
MarianD
fonte
Vale a pena ressaltar que o código do estilizador como este deve ser executado, e só tem efeito no notebook Jupyter, e tem efeito zero quando executado no console ou iPython . O OP não especificava "sob Jupyter", então esta pode ou não ser uma solução viável dependendo de sua configuração. Muito código de ciência de dados é copiado e colado e as suposições específicas do Jupyter não são especificadas explicitamente, então as pessoas se perguntam por que o código do estilizador "não funciona" quando executado em seu ambiente (console).
smci
@smci, não é explicitamente mencionado no segundo parágrafo da minha resposta? Na forma de ifdeclaração condicional , tão conhecida por todos os programadores? - Apesar de tudo obrigado pelo seu comentário, pode ser útil para algumas pessoas.
MarianD
não, isso é muito obscuro, também enterrado. A pergunta original não supunha nada sobre o Jupyter, e o OP e alguns usuários podem nem mesmo ter o Jupyter disponível para eles. Sua resposta precisaria dizer em negrito sua primeira linha "A abordagem seguinte (estilo) só funciona no notebook Jupyter e não terá nenhum efeito quando executada fora do notebook Jupyter" . (Em blogs e sites de ciência de dados, vejo diariamente pessoas postando código Jupyter em ambientes não Jupyter e se perguntando por que ele não funciona).
smci
Legal. Eu também sugiro que você adicione todas as (muitas) armadilhas que você identificou nas outras abordagens de "converter para string-com-strftime-então-voltar-com-pd.to_datetime". Pelo menos, é preciso mencionar o levantamento e a captura de exceções. Além disso, pd.to_datetime()tem os argumentos errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exactpara controlar o quão preciso e tolerante a exceções ele é, e se saídas inválidas são coagidas NaTou não. O que o torna mais complicado em conjuntos de dados do "mundo real" são os formatos, horários, fusos horários mistos / ausentes / incompletos, etc; exceções não são necessariamente coisas ruins.
smci
... ou então posso escrever isso como um acúmulo de armadilhas nas abordagens não-Jupyter.
smci
1

O código abaixo muda para o tipo 'data e hora' e também para formatos na string de formato fornecida. Funciona bem!

df['DOB']=pd.to_datetime(df['DOB'].dt.strftime('%m/%d/%Y'))
San
fonte
2
mude para este:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y')
John Doe
Não! - Por que converter datetime para string e depois de volta para datetime ? Veja meus comentários para outras respostas.
MarianD
1

Você pode tentar isso para converter o formato de data para DD-MM-AAAA:

df['DOB'] = pd.to_datetime(df['DOB'], dayfirst = True)
Ashu007
fonte
Não! dayfirst=Trueé apenas a especificação de uma ordem de análise de data, por exemplo, aquela string de data ambivalente como "2-1-2019" será analisada como 2 de janeiro de 2019, e não como 1 de fevereiro de 2019. Nada mais, nenhuma alteração para a formatação de saída .
MarianD