Não perca a python3.7 + solução abaixo para inverter isoformat ()
Brad M
2
Esta questão não deve ser encerrada como uma brincadeira com a postagem vinculada. Como este está pedindo para analisar uma sequência de tempo ISO 8601 (que não era suportada nativamente pelo python antes da versão 3.7), a outra é formatar um objeto datetime em uma sequência de época usando um método obsoleto.
abccd
Respostas:
462
O pacote python-dateutil pode analisar não apenas as seqüências de data e hora RFC 3339 como a da pergunta, mas também outras seqüências de data e hora ISO 8601 que não estão em conformidade com a RFC 3339 (como aquelas sem deslocamento UTC ou que representam apenas uma data).
>>>import dateutil.parser>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686Z')# RFC 3339 format
datetime.datetime(2008,9,3,20,56,35,450686, tzinfo=tzutc())>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686')# ISO 8601 extended format
datetime.datetime(2008,9,3,20,56,35,450686)>>> dateutil.parser.isoparse('20080903T205635.450686')# ISO 8601 basic format
datetime.datetime(2008,9,3,20,56,35,450686)>>> dateutil.parser.isoparse('20080903')# ISO 8601 basic format, date only
datetime.datetime(2008,9,3,0,0)
Observe que dateutil.parser.isoparseé presumivelmente mais rigoroso do que o mais hacky dateutil.parser.parse, mas ambos são bastante tolerantes e tentarão interpretar a string que você passa. Se você deseja eliminar a possibilidade de erros de leitura, precisará usar algo mais rigoroso do que qualquer um deles. funções.
Para o preguiçoso, ele é instalado via python-dateutilnão dateutil, então: pip install python-dateutil.
Cod3monk3y
29
Esteja avisado de que o dateutil.parserintencionalmente é hacky: ele tenta adivinhar o formato e cria suposições inevitáveis (personalizáveis apenas à mão) em casos ambíguos. Portanto, APENAS use-o se você precisar analisar entradas de formato desconhecido e estiver bem para tolerar erros de leitura ocasionais.
precisa saber é o seguinte
2
Acordado. Um exemplo está passando uma "data" de 9999. Isso retornará o mesmo que datetime (9999, mês atual, dia atual). Não é uma data válida na minha opinião.
timbó
1
@ivan_pozdeev que pacote você recomendaria para a análise sem adivinhação?
Isso é estranho. Porque a datetimepode conter ae tzinfo, assim, datetime.fromisoformat()gerar um fuso horário, mas não analisa o tzinfo? parece ser um bug ..
Hendy Irawan
20
Não perca essa nota na documentação, isso não aceita todas as seqüências ISO 8601 válidas, apenas as geradas por isoformat. Ele não aceita o exemplo da pergunta "2008-09-03T20:56:35.450686Z"por causa do rastreamento Z, mas aceita "2008-09-03T20:56:35.450686".
Flimm 23/08/19
26
Para suportar adequadamente o Zscript de entrada, pode ser modificado com date_string.replace("Z", "+00:00").
jox
7
Observe que, por segundos, ele lida apenas com exatamente 0, 3 ou 6 casas decimais. Se os dados de entrada tiverem 1, 2, 4, 5, 7 ou mais casas decimais, a análise falhará!
Felk 28/05/19
1
@JDOaktown Este exemplo usa a biblioteca de data e hora nativa do Python, não o analisador do dateutil. Na verdade, ele falhará se as casas decimais não forem 0, 3 ou 6 com essa abordagem.
precisa saber é
174
Observe no Python 2.6+ e Py3K, o caractere% f captura microssegundos.
Nota - se estiver usando datações ingênuas - acho que você não recebe TZ - Z pode não corresponder a nada.
Danny Staple
24
Esta resposta (em sua forma atual editada) depende da codificação codificada de um deslocamento UTC específico (ou seja, "Z", que significa +00: 00) na cadeia de caracteres do formato. Essa é uma péssima idéia, pois falhará na análise de qualquer data e hora com um deslocamento UTC diferente e gerará uma exceção. Veja minha resposta que descreve como a análise do RFC 3339 strptimeé de fato impossível.
Mark Amery
1
no meu caso% f microssegundos capturados em vez de Z, datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f') de modo que este fez o truque
ashim888
Py3K significa Python 3000?!?
Robino 13/11/19
2
@Robino IIRC, "Python 3000" é um nome antigo para o que agora é conhecido como Python 3.
Supondo que você queira oferecer suporte ao formato RFC 3339 completo, incluindo suporte a compensações UTC diferentes de zero, o código sugerido por essas respostas não funcionará. Na verdade, ele não pode funcionar, porque strptimeé impossível analisar a sintaxe da RFC 3339 . As seqüências de formato usadas pelo módulo de data e hora do Python são incapazes de descrever a sintaxe do RFC 3339.
O problema são compensações de UTC. O RFC 3339 Internet Data / Time Format requer que cada data-hora inclui um UTC offset, e que estas compensações tanto pode ser Z(abreviação de "tempo de Zulu") ou +HH:MMou -HH:MMformato, como +05:00ou -10:30.
Conseqüentemente, essas são todas as datas válidas da RFC 3339:
2008-09-03T20:56:35.450686Z
2008-09-03T20:56:35.450686+05:00
2008-09-03T20:56:35.450686-10:30
Infelizmente, as seqüências de caracteres de formato usadas strptimee strftimenão possuem nenhuma diretiva que corresponda às compensações do UTC no formato RFC 3339. Uma lista completa das diretivas suportadas pode ser encontrada em https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior , e a única diretiva de deslocamento UTC incluída na lista é %z:
% z
Deslocamento UTC no formato + HHMM ou -HHMM (sequência vazia se o objeto for ingênuo).
Exemplo: (vazio), +0000, -0400, +1030
Isso não corresponde ao formato de um deslocamento da RFC 3339 e, de fato, se tentarmos usar %za string de formato e analisar uma data da RFC 3339, ocorreremos falhas:
>>> from datetime import datetime
>>> datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686Z' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
(Na verdade, o que foi mostrado acima é exatamente o que você verá no Python 3. No Python 2, falharemos por uma razão ainda mais simples, que é que strptimenão implementa a %zdiretiva no Python 2. )
As várias respostas aqui que recomendam strptimetoda a solução para isso, incluindo um literal Zem sua sequência de formatação, que corresponde à Zsequência de data / hora do exemplo do solicitante da pergunta (e a descarta, produzindo um datetimeobjeto sem um fuso horário):
Como isso descarta as informações do fuso horário incluídas na cadeia de data e hora original, é questionável se devemos considerar mesmo esse resultado correto. Porém, o mais importante é que, como essa abordagem envolve a codificação embutida de um deslocamento UTC específico na cadeia de caracteres de formato , ela sufocará o momento em que tentar analisar qualquer data e hora da RFC 3339 com um deslocamento UTC diferente:
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%fZ")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%fZ'
A menos que você tenha certeza de que precisa apenas suportar dados RFC 3339 no horário Zulu, e não aqueles com outros desvios de fuso horário, não use strptime. Use uma das muitas outras abordagens descritas nas respostas aqui.
É incompreensível que o strptime não tenha uma diretiva para informações de fuso horário no formato ISO e por que não pode ser analisado. Incrível.
Csaba Toth
2
@CsabaToth Concordo totalmente - se eu tiver algum tempo para matar, talvez eu tente adicioná-lo ao idioma. Ou você poderia fazê-lo, se estivesse tão inclinado - vejo que você tem alguma experiência em C, diferente de mim.
Mark Amery
1
@CsabaToth - Por que incrível? Funciona bem o suficiente para a maioria das pessoas, ou eles acharam uma solução fácil. Se você precisar do recurso, ele é de código aberto e você pode adicioná-lo. Ou pague alguém para fazer isso por você. Por que alguém deve oferecer seu próprio tempo livre para resolver seus problemas específicos? Deixe a fonte estar com você.
Peter M. - significa Monica
2
@PeterMasiar Incrível porque geralmente se descobre que as coisas em python foram implementadas de maneira cuidadosa e completa. Ficamos estragados com essa atenção aos detalhes e, por isso, quando nos deparamos com algo na linguagem "não-tônica", jogamos nossos brinquedos fora do carrinho, como estou prestes a fazer agora. Whaaaaaaaaaa Whaa wahaaaaa :-(
Robino
2
strptime()no Python 3.7 agora suporta tudo descrito como impossível nesta resposta (literal 'Z' e ':' no deslocamento do fuso horário). Infelizmente, há outro caso de esquina que torna o RFC 3339 fundamentalmente incompatível com a ISO 8601, a saber, o primeiro permite um deslocamento de fuso horário nulo negativo -00: 00 e o posterior não.
SergiyKolesnikov
75
Experimente o módulo iso8601 ; faz exatamente isso.
Existem várias outras opções mencionadas na página WorkingWithTime no wiki do python.org.
A pergunta não era "como analiso datas ISO 8601", mas "como analiso esse formato exato de data".
22912 Nicholas Riley
3
@tiktak O OP perguntou "Preciso analisar seqüências de caracteres como X" e minha resposta a isso, depois de tentar as duas bibliotecas, é usar outra, porque o iso8601 ainda tem questões importantes em aberto. Meu envolvimento ou a falta dele em um projeto desse tipo não tem nenhuma relação com a resposta.
Tobia
2
Esteja ciente de que a versão do pip do iso8601 não é atualizada desde 2007 e tem alguns erros sérios que são pendentes. Eu recomendo a aplicação de algum crítico dos patches-se ou encontrar um dos muitos garfos github que já o fizeram github.com/keithhackbarth/pyiso8601-strict
keithhackbarth
6
O iso8601 , também conhecido como pyiso8601 , foi atualizado recentemente em fevereiro de 2014. A versão mais recente suporta um conjunto muito mais amplo de seqüências de caracteres ISO 8601. Eu tenho usado com bons resultados em alguns dos meus projetos.
Dave Hein
34
import re, datetime
s = "2008-09-03T20: 56: 35.450686Z"
d = datetime.datetime (* map (int, re.split ('[^ \ d]', s) [: - 1])))
Discordo, isso é praticamente ilegível e, até onde sei, não leva em consideração o Zulu (Z), que torna essa data e hora ingênuas, mesmo que os dados do fuso horário tenham sido fornecidos.
Umbrae
14
Acho bastante legível. De fato, é provavelmente a maneira mais fácil e com melhor desempenho de fazer a conversão sem instalar pacotes adicionais.
Tobia
2
Isso é equivalente a d = datetime.datetime (* map (int, re.split ('\ D', s) [: - 1]))) suponho.
Xuan
4
uma variação:datetime.datetime(*map(int, re.findall('\d+', s))
jfs 16/05
3
Isso resulta em um objeto datetime ingênuo sem fuso horário, certo? Então o bit UTC se perde na tradução?
W00t
32
Qual é o erro exato que você recebe? É como o seguinte?
>>> datetime.datetime.strptime("2008-08-12T12:20:30.656234Z","%Y-%m-%dT%H:%M:%S.Z")ValueError: time data did not match format: data=2008-08-12T12:20:30.656234Z fmt=%Y-%m-%dT%H:%M:%S.Z
Se sim, você pode dividir sua sequência de entrada em "." E adicionar os microssegundos à data e hora que você obteve.
Você não pode simplesmente retirar o .Z porque significa fuso horário e pode ser diferente. Preciso converter a data no fuso horário UTC.
Alexander Artemenko
Um objeto de data e hora simples não tem conceito de fuso horário. Se todos os seus horários estão terminando em "Z", todas as vezes em que você obtém são UTC (hora do Zulu).
tzot 24/09/08
se o fuso horário for diferente de ""ou "Z", deverá ser um deslocamento em horas / minutos, que pode ser diretamente adicionado / subtraído do objeto datetime. você pode criar uma subclasse tzinfo para lidar com isso, mas isso provavelmente não é recomendado.
SingleNegationElimination
8
Além disso, "% f" é o especificador de microssegundos, portanto, uma string de strptime (ingênua ao fuso horário) se parece com: "% Y-% m-% dT% H:% M:% S.% f".
quodlibetor
1
Isso gerará uma exceção se a sequência de data / hora especificada tiver um deslocamento UTC diferente de "Z". Ele não suporta todo o formato RFC 3339 e é uma resposta inferior a outras pessoas que lidam com compensações UTC corretamente.
Mark Amery
25
A partir do Python 3.7, o strptime suporta delimitadores de dois pontos nos desvios do UTC ( origem ). Então você pode usar:
Mas, em 3,7, você também tem datetime.fromisoformat()que manipula strings como sua entrada automaticamente datetime.datetime.isoformat('2018-01-31T09:24:31.488670+00:00').
Martijn Pieters
2
Bom ponto. Eu concordo, eu recomendo usar datetime.fromisoformat()edatetime.isoformat()
Andreas Profous
19
Atualmente, o Arrow também pode ser usado como uma solução de terceiros:
>>>import arrow
>>> date = arrow.get("2008-09-03T20:56:35.450686Z")>>> date.datetime
datetime.datetime(2008,9,3,20,56,35,450686, tzinfo=tzutc())
Basta usar python-dateutil - a seta requer python-dateutil.
Danizen
A Arrow agora suporta ISO8601. Os problemas mencionados estão encerrados.
Altus
18
Basta usar o python-dateutilmódulo:
>>>import dateutil.parser as dp
>>> t ='1984-06-02T19:05:00.000Z'>>>parsed_t= dp.parse(t)>>>print(parsed_t)
datetime.datetime(1984,6,2,19,5, tzinfo=tzutc())
Onde você o vê analisando em segundos? Eu encontrei este artigo tentando obter um tempo de época, então imaginei que outra pessoa também estaria.
precisa saber é o seguinte
1
Isso não é UTC no meu sistema. Em vez disso, a saída em segundos é a hora da época unix, como se a data estivesse no meu fuso horário local.
Elliot
1
Esta resposta é incorreta e não deve ser aceita. Provavelmente toda a questão deve ser marcada como uma duplicata de stackoverflow.com/questions/11743019/…
tripleee
@tripleee Na verdade, acabei de verificar o código e ele parece retornar a resposta correta: 455051100(verificado no epochconverter.com ) ,,, a menos que esteja faltando alguma coisa?
Blairg23
13
Se você não quiser usar o dateutil, tente esta função:
def from_utc(utcTime,fmt="%Y-%m-%dT%H:%M:%S.%fZ"):"""
Convert UTC time string to time.struct_time
"""# change datetime.datetime to time, return time.struct_time typereturn datetime.datetime.strptime(utcTime, fmt)
Esta resposta depende da codificação embutida de um deslocamento UTC específico (ou seja, "Z", que significa +00: 00) na cadeia de formato passada para strptime. Essa é uma péssima idéia, pois falhará na análise de qualquer data e hora com um deslocamento UTC diferente e gerará uma exceção. Veja minha resposta que descreve como analisar o RFC 3339 com strptime é de fato impossível.
Mark Amery
1
É codificado, mas é suficiente para o caso em que você precisa analisar apenas o zulu.
Sasha
1
@alexander yes - que pode ser o caso se, por exemplo, você souber que sua string de data foi gerada com o toISOStringmétodo JavaScript . Mas não há menção à limitação das datas do horário do Zulu nesta resposta, nem a pergunta indica que é tudo o que é necessário, e o uso dateutilé geralmente igualmente conveniente e menos restrito no que ele pode analisar.
Mark Amery
11
Se você estiver trabalhando com o Django, ele fornece o módulo dateparse que aceita vários formatos semelhantes ao formato ISO, incluindo o fuso horário.
Se você não estiver usando o Django e não quiser usar uma das outras bibliotecas mencionadas aqui, provavelmente poderá adaptar o código-fonte do Django para dateparse no seu projeto.
Parece uma ótima biblioteca! Para aqueles que desejam otimizar a análise ISO8601 no Google App Engine, infelizmente, não podemos usá-lo, pois é uma biblioteca C, mas seus benchmarks foram úteis para mostrar que o nativo datetime.strptime()é a próxima solução mais rápida. Obrigado por reunir todas essas informações!
21419 hamx0r #
3
@ hamx0r, esteja ciente de que datetime.strptime()não é uma biblioteca de análise ISO 8601 completa. Se você estiver no Python 3.7, poderá usar o datetime.fromisoformat()método, que é um pouco mais flexível. Você pode estar interessado nesta lista mais completa de analisadores que deve ser mesclada no README do ciso8601 em breve.
Movmeyer
O ciso8601 funciona bem, mas é preciso primeiro "instalar pip pytz", porque não é possível analisar um carimbo de data / hora com informações de fuso horário sem a dependência do pytz. O exemplo seria: dob = ciso8601.parse_datetime (resultado ['dob'] ['date'])
Esta resposta depende da codificação embutida de um deslocamento UTC específico (ou seja, "Z", que significa +00: 00) na cadeia de formato passada para strptime. Essa é uma péssima idéia, pois falhará na análise de qualquer data e hora com um deslocamento UTC diferente e gerará uma exceção. Veja minha resposta que descreve como analisar o RFC 3339 com strptime é de fato impossível.
Mark Amery
1
Em teoria, sim, isso falha. Na prática, nunca encontrei uma data no formato ISO 8601 que não estava no tempo do Zulu. Para minha necessidade ocasional, isso funciona muito bem e não depende de alguma biblioteca externa.
Benjamin Riggs
4
você poderia usar em timezone.utcvez de timezone(timedelta(0)). Além disso, o código funciona em Python 2.6+ (pelo menos) se você fornecer utctzinfo objeto
JFS
Não importa se você o encontrou, ele não corresponde à especificação.
Theannouncer 25/02/19
Você pode usar o %Zfuso horário for nas versões mais recentes do Python.
26419 sventechie
7
Eu sou o autor de iso8601 utils. Pode ser encontrado no GitHub ou no PyPI . Veja como você pode analisar seu exemplo:
Uma maneira simples de converter uma sequência de datas do tipo ISO 8601 em um carimbo de data / hora UNIX ou datetime.datetimeobjeto em todas as versões suportadas do Python sem instalar módulos de terceiros é usar o analisador de datas do SQLite .
#!/usr/bin/env pythonfrom __future__ import with_statement, division, print_function
import sqlite3
import datetime
testtimes =["2016-08-25T16:01:26.123456Z","2016-08-25T16:01:29",]
db = sqlite3.connect(":memory:")
c = db.cursor()for timestring in testtimes:
c.execute("SELECT strftime('%s', ?)",(timestring,))
converted = c.fetchone()[0]print("%s is %s after epoch"%(timestring, converted))
dt = datetime.datetime.fromtimestamp(int(converted))print("datetime is %s"% dt)
Resultado:
2016-08-25T16:01:26.123456Zis1472140886 after epoch
datetime is2016-08-2512:01:262016-08-25T16:01:29is1472140889 after epoch
datetime is2016-08-2512:01:29
Codifiquei um analisador para o padrão ISO 8601 e o coloquei no GitHub: https://github.com/boxed/iso8601 . Essa implementação suporta tudo na especificação, exceto por durações, intervalos, intervalos periódicos e datas fora do período suportado do módulo de data e hora do Python.
Como a ISO 8601 permite que muitas variações de dois pontos e hífens opcionais estejam presentes, basicamente CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]. Se você deseja usar o strptime, é necessário eliminar essas variações primeiro.
O objetivo é gerar um objeto utc datetime.
Se você quer apenas um caso básico que funcione para o UTC com o sufixo Z, como 2016-06-29T19:36:29.3453Z:
Se você deseja lidar com deslocamentos de fuso horário como 2016-06-29T19:36:29.3453-0400ou 2008-09-03T20:56:35.450686+05:00use o seguinte. Isso converterá todas as variações em algo sem delimitadores de variáveis, como 20080903T205635.450686+0500torná-lo mais consistente / mais fácil de analisar.
import re
# this regex removes all colons and all # dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))",'', timestamp)
datetime.datetime.strptime(conformed_timestamp,"%Y%m%dT%H%M%S.%f%z")
Se o seu sistema não suportar a %zdiretiva strptime (você vê algo assim ValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'), será necessário compensar manualmente a hora Z(UTC). A nota %zpode não funcionar em seu sistema nas versões python <3, pois depende do suporte da biblioteca c, que varia de acordo com o tipo de compilação do sistema / python (por exemplo, Jython, Cython, etc.).
import re
import datetime
# this regex removes all colons and all # dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))",'', timestamp)# split on the offset to remove it. use a capture group to keep the delimiter
split_timestamp = re.split(r"[+|-]",conformed_timestamp)
main_timestamp = split_timestamp[0]if len(split_timestamp)==3:
sign = split_timestamp[1]
offset = split_timestamp[2]else:
sign =None
offset =None# generate the datetime object without the offset at UTC time
output_datetime = datetime.datetime.strptime(main_timestamp +"Z","%Y%m%dT%H%M%S.%fZ")if offset:# create timedelta based on offset
offset_delta = datetime.timedelta(hours=int(sign+offset[:-2]), minutes=int(sign+offset[-2:]))# offset datetime with timedelta
output_datetime = output_datetime + offset_delta
classFixedOffset(tzinfo):"""Fixed offset in minutes: `time = utc_time + utc_offset`."""def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
hours, minutes = divmod(offset,60)#NOTE: the last part is to remind about deprecated POSIX GMT+h timezones# that have the opposite sign in the name;# the corresponding numeric value is not used e.g., no minutes
self.__name ='<%+03d%02d>%+d'%(hours, minutes,-hours)def utcoffset(self, dt=None):return self.__offset
def tzname(self, dt=None):return self.__name
def dst(self, dt=None):return timedelta(0)def __repr__(self):return'FixedOffset(%d)'%(self.utcoffset().total_seconds()/60)def __getinitargs__(self):return(self.__offset.total_seconds()/60,)def parse_isoformat_datetime(isodatetime):try:return datetime.strptime(isodatetime,'%Y-%m-%dT%H:%M:%S.%f')exceptValueError:passtry:return datetime.strptime(isodatetime,'%Y-%m-%dT%H:%M:%S')exceptValueError:pass
pat = r'(.*?[+-]\d{2}):(\d{2})'
temp = re.sub(pat, r'\1\2', isodatetime)
naive_date_str = temp[:-5]
offset_str = temp[-5:]
naive_dt = datetime.strptime(naive_date_str,'%Y-%m-%dT%H:%M:%S.%f')
offset = int(offset_str[-4:-2])*60+ int(offset_str[-2:])if offset_str[0]=="-":
offset =-offset
return naive_dt.replace(tzinfo=FixedOffset(offset))
Respostas:
O pacote python-dateutil pode analisar não apenas as seqüências de data e hora RFC 3339 como a da pergunta, mas também outras seqüências de data e hora ISO 8601 que não estão em conformidade com a RFC 3339 (como aquelas sem deslocamento UTC ou que representam apenas uma data).
Observe que
dateutil.parser.isoparse
é presumivelmente mais rigoroso do que o mais hackydateutil.parser.parse
, mas ambos são bastante tolerantes e tentarão interpretar a string que você passa. Se você deseja eliminar a possibilidade de erros de leitura, precisará usar algo mais rigoroso do que qualquer um deles. funções.O nome Pypi é
python-dateutil
, nãodateutil
(obrigado code3monk3y ):Se você estiver usando Python 3.7, ter um olhar para esta resposta sobre
datetime.datetime.fromisoformat
.fonte
python-dateutil
nãodateutil
, então:pip install python-dateutil
.dateutil.parser
intencionalmente é hacky: ele tenta adivinhar o formato e cria suposições inevitáveis (personalizáveis apenas à mão) em casos ambíguos. Portanto, APENAS use-o se você precisar analisar entradas de formato desconhecido e estiver bem para tolerar erros de leitura ocasionais.Novo no Python 3.7+
A
datetime
biblioteca padrão introduziu uma função para inversãodatetime.isoformat()
.Exemplo de uso:
fonte
datetime
pode conter aetzinfo
, assim,datetime.fromisoformat()
gerar um fuso horário, mas não analisa o tzinfo? parece ser um bug ..isoformat
. Ele não aceita o exemplo da pergunta"2008-09-03T20:56:35.450686Z"
por causa do rastreamentoZ
, mas aceita"2008-09-03T20:56:35.450686"
.Z
script de entrada, pode ser modificado comdate_string.replace("Z", "+00:00")
.Observe no Python 2.6+ e Py3K, o caractere% f captura microssegundos.
Veja a edição aqui
fonte
strptime
é de fato impossível.datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f')
de modo que este fez o truqueVárias respostas aqui sugerem o uso
datetime.datetime.strptime
para analisar as datas RFC 3339 ou ISO 8601 com fusos horários, como o exibido na pergunta:Esta é uma má ideia.
Supondo que você queira oferecer suporte ao formato RFC 3339 completo, incluindo suporte a compensações UTC diferentes de zero, o código sugerido por essas respostas não funcionará. Na verdade, ele não pode funcionar, porque
strptime
é impossível analisar a sintaxe da RFC 3339 . As seqüências de formato usadas pelo módulo de data e hora do Python são incapazes de descrever a sintaxe do RFC 3339.O problema são compensações de UTC. O RFC 3339 Internet Data / Time Format requer que cada data-hora inclui um UTC offset, e que estas compensações tanto pode ser
Z
(abreviação de "tempo de Zulu") ou+HH:MM
ou-HH:MM
formato, como+05:00
ou-10:30
.Conseqüentemente, essas são todas as datas válidas da RFC 3339:
2008-09-03T20:56:35.450686Z
2008-09-03T20:56:35.450686+05:00
2008-09-03T20:56:35.450686-10:30
Infelizmente, as seqüências de caracteres de formato usadas
strptime
estrftime
não possuem nenhuma diretiva que corresponda às compensações do UTC no formato RFC 3339. Uma lista completa das diretivas suportadas pode ser encontrada em https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior , e a única diretiva de deslocamento UTC incluída na lista é%z
:Isso não corresponde ao formato de um deslocamento da RFC 3339 e, de fato, se tentarmos usar
%z
a string de formato e analisar uma data da RFC 3339, ocorreremos falhas:(Na verdade, o que foi mostrado acima é exatamente o que você verá no Python 3. No Python 2, falharemos por uma razão ainda mais simples, que é que
strptime
não implementa a%z
diretiva no Python 2. )As várias respostas aqui que recomendam
strptime
toda a solução para isso, incluindo um literalZ
em sua sequência de formatação, que corresponde àZ
sequência de data / hora do exemplo do solicitante da pergunta (e a descarta, produzindo umdatetime
objeto sem um fuso horário):Como isso descarta as informações do fuso horário incluídas na cadeia de data e hora original, é questionável se devemos considerar mesmo esse resultado correto. Porém, o mais importante é que, como essa abordagem envolve a codificação embutida de um deslocamento UTC específico na cadeia de caracteres de formato , ela sufocará o momento em que tentar analisar qualquer data e hora da RFC 3339 com um deslocamento UTC diferente:
A menos que você tenha certeza de que precisa apenas suportar dados RFC 3339 no horário Zulu, e não aqueles com outros desvios de fuso horário, não use
strptime
. Use uma das muitas outras abordagens descritas nas respostas aqui.fonte
strptime()
no Python 3.7 agora suporta tudo descrito como impossível nesta resposta (literal 'Z' e ':' no deslocamento do fuso horário). Infelizmente, há outro caso de esquina que torna o RFC 3339 fundamentalmente incompatível com a ISO 8601, a saber, o primeiro permite um deslocamento de fuso horário nulo negativo -00: 00 e o posterior não.Experimente o módulo iso8601 ; faz exatamente isso.
Existem várias outras opções mencionadas na página WorkingWithTime no wiki do python.org.
fonte
iso8601.parse_date("2008-09-03T20:56:35.450686Z")
fonte
datetime.datetime(*map(int, re.findall('\d+', s))
Qual é o erro exato que você recebe? É como o seguinte?
Se sim, você pode dividir sua sequência de entrada em "." E adicionar os microssegundos à data e hora que você obteve.
Tente o seguinte:
fonte
""
ou"Z"
, deverá ser um deslocamento em horas / minutos, que pode ser diretamente adicionado / subtraído do objeto datetime. você pode criar uma subclasse tzinfo para lidar com isso, mas isso provavelmente não é recomendado.A partir do Python 3.7, o strptime suporta delimitadores de dois pontos nos desvios do UTC ( origem ). Então você pode usar:
EDITAR:
Conforme apontado por Martijn, se você criou o objeto datetime usando isoformat (), pode simplesmente usar datetime.fromisoformat ()
fonte
datetime.fromisoformat()
que manipula strings como sua entrada automaticamentedatetime.datetime.isoformat('2018-01-31T09:24:31.488670+00:00')
.datetime.fromisoformat()
edatetime.isoformat()
Atualmente, o Arrow também pode ser usado como uma solução de terceiros:
fonte
Basta usar o
python-dateutil
módulo:Documentação
fonte
455051100
(verificado no epochconverter.com ) ,,, a menos que esteja faltando alguma coisa?Se você não quiser usar o dateutil, tente esta função:
Teste:
Resultado:
fonte
strptime
. Essa é uma péssima idéia, pois falhará na análise de qualquer data e hora com um deslocamento UTC diferente e gerará uma exceção. Veja minha resposta que descreve como analisar o RFC 3339 com strptime é de fato impossível.toISOString
método JavaScript . Mas não há menção à limitação das datas do horário do Zulu nesta resposta, nem a pergunta indica que é tudo o que é necessário, e o usodateutil
é geralmente igualmente conveniente e menos restrito no que ele pode analisar.Se você estiver trabalhando com o Django, ele fornece o módulo dateparse que aceita vários formatos semelhantes ao formato ISO, incluindo o fuso horário.
Se você não estiver usando o Django e não quiser usar uma das outras bibliotecas mencionadas aqui, provavelmente poderá adaptar o código-fonte do Django para dateparse no seu projeto.
fonte
DateTimeField
usa isso quando você define um valor de string.Eu descobri que o ciso8601 é a maneira mais rápida de analisar os carimbos de data / hora ISO 8601. Como o nome sugere, ele é implementado em C.
O README do GitHub Repo mostra sua aceleração> 10x em relação a todas as outras bibliotecas listadas nas outras respostas.
Meu projeto pessoal envolveu muita análise da ISO 8601. Foi bom poder mudar a chamada e ir 10 vezes mais rápido. :)
Edit: Desde então, me tornei um mantenedor do ciso8601. Agora está mais rápido do que nunca!
fonte
datetime.strptime()
é a próxima solução mais rápida. Obrigado por reunir todas essas informações!datetime.strptime()
não é uma biblioteca de análise ISO 8601 completa. Se você estiver no Python 3.7, poderá usar odatetime.fromisoformat()
método, que é um pouco mais flexível. Você pode estar interessado nesta lista mais completa de analisadores que deve ser mesclada no README do ciso8601 em breve.Isso funciona para o stdlib no Python 3.2 em diante (assumindo que todos os timestamps são UTC):
Por exemplo,
fonte
strptime
. Essa é uma péssima idéia, pois falhará na análise de qualquer data e hora com um deslocamento UTC diferente e gerará uma exceção. Veja minha resposta que descreve como analisar o RFC 3339 com strptime é de fato impossível.timezone.utc
vez detimezone(timedelta(0))
. Além disso, o código funciona em Python 2.6+ (pelo menos) se você fornecerutc
tzinfo objeto%Z
fuso horário for nas versões mais recentes do Python.Eu sou o autor de iso8601 utils. Pode ser encontrado no GitHub ou no PyPI . Veja como você pode analisar seu exemplo:
fonte
Uma maneira simples de converter uma sequência de datas do tipo ISO 8601 em um carimbo de data / hora UNIX ou
datetime.datetime
objeto em todas as versões suportadas do Python sem instalar módulos de terceiros é usar o analisador de datas do SQLite .Resultado:
fonte
Codifiquei um analisador para o padrão ISO 8601 e o coloquei no GitHub: https://github.com/boxed/iso8601 . Essa implementação suporta tudo na especificação, exceto por durações, intervalos, intervalos periódicos e datas fora do período suportado do módulo de data e hora do Python.
Os testes estão incluídos! : P
fonte
A função parse_datetime () do Django suporta datas com deslocamentos UTC:
Portanto, poderia ser usado para analisar datas ISO 8601 em campos de todo o projeto:
fonte
Como a ISO 8601 permite que muitas variações de dois pontos e hífens opcionais estejam presentes, basicamente
CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]
. Se você deseja usar o strptime, é necessário eliminar essas variações primeiro.O objetivo é gerar um objeto utc datetime.
Se você quer apenas um caso básico que funcione para o UTC com o sufixo Z, como
2016-06-29T19:36:29.3453Z
:Se você deseja lidar com deslocamentos de fuso horário como
2016-06-29T19:36:29.3453-0400
ou2008-09-03T20:56:35.450686+05:00
use o seguinte. Isso converterá todas as variações em algo sem delimitadores de variáveis, como20080903T205635.450686+0500
torná-lo mais consistente / mais fácil de analisar.Se o seu sistema não suportar a
%z
diretiva strptime (você vê algo assimValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'
), será necessário compensar manualmente a horaZ
(UTC). A nota%z
pode não funcionar em seu sistema nas versões python <3, pois depende do suporte da biblioteca c, que varia de acordo com o tipo de compilação do sistema / python (por exemplo, Jython, Cython, etc.).fonte
Para algo que funcione com a biblioteca padrão 2.X, tente:
calendar.timegm é a versão gm ausente do time.mktime.
fonte
O python-dateutil lançará uma exceção ao analisar cadeias de datas inválidas, portanto, você pode capturar a exceção.
fonte
Atualmente, existe o Maya: Datetimes for Humans ™ , do autor do popular pacote Requests: HTTP for Humans ™:
fonte
Uma outra maneira é usar o analisador especializado para ISO-8601 é usar a função isoparse do analisador dateutil:
Resultado:
Essa função também é mencionada na documentação da função Python padrão datetime.fromisoformat :
fonte
Graças à excelente resposta de Mark Amery, criei a função para explicar todos os possíveis formatos ISO de data e hora:
fonte
Note que devemos procurar se a string não terminar
Z
, poderíamos analisar usando%z
.fonte
Inicialmente, tentei com:
Mas isso não funcionou em fusos horários negativos. No entanto, isso funcionou bem, no Python 3.7.3:
Alguns testes, observe que a saída difere apenas pela precisão de microssegundos. Tenho 6 dígitos de precisão na minha máquina, mas YMMV:
fonte
frozenset(('+', '-'))
? Uma tupla normal não deveria('+', '-')
ser capaz de realizar a mesma coisa?