Tempo ISO (ISO 8601) em Python


340

Eu tenho um arquivo No Python, eu gostaria de aproveitar o tempo de criação e convertê-lo em uma sequência de tempo ISO (ISO 8601) , preservando o fato de que ele foi criado no fuso horário oriental (ET) .

Como tomo o ctime do arquivo e o converto em uma seqüência de horário ISO que indica o fuso horário do leste (e leva em consideração o horário de verão, se necessário)?



11
@ Nick- Link útil, mas não duplicado - ele está perguntando sobre a conversão para o outro lado.
Yarin

1
@ Joseph- Eu só perguntei isso em relação a RFC 3999- deve trabalhar para isso - Gerar RFC 3339 timestamp em Python
Yarin

Respostas:


560

Local para ISO 8601:

import datetime
datetime.datetime.now().isoformat()
>>> 2020-03-20T14:28:23.382748

UTC para ISO 8601:

import datetime
datetime.datetime.utcnow().isoformat()
>>> 2020-03-20T01:30:08.180856

Local para ISO 8601 sem microssegundo:

import datetime
datetime.datetime.now().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:30:43

UTC para ISO 8601 com informações de fuso horário (Python 3):

import datetime
datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat()
>>> 2020-03-20T01:31:12.467113+00:00

UTC para ISO 8601 com informações de fuso horário local sem microssegundo (Python 3):

import datetime
datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:31:43+13:00

Local para ISO 8601 com informações de fuso horário (Python 3):

import datetime
datetime.datetime.now().astimezone().isoformat()
>>> 2020-03-20T14:32:16.458361+13:00

Observe que há um erro ao usar astimezone()no utc time. Isso fornece um resultado incorreto:

datetime.datetime.utcnow().astimezone().isoformat() #Incorrect result

Para Python 2, veja e use pytz .


17
.isoformat()pode .isoformat(' ')
usar

5
@ThorSummoner bom saber! Mas tome cuidado para que a troca do separador não atenda mais à ISO-8601 ... o que faz pouco sentido (além disso, existem maneiras melhores de imprimir datas, mas essa não é a questão aqui). RFC
estani

4
O espaço é permitido como parte do padrão ISO-8601. It is permitted to omit the 'T' character by mutual agreement.
raychi 7/09/16

4
@raychi Sempre é permitido alterar um padrão por acordo mútuo (que em muitos casos quebra o padrão, mas quem se importa se for acordo mútuo, certo?). Meu 2c: apenas não, deixe como está.
estani 8/09/16

14
Esta resposta está errada porque datetime.datetime.now (). Isoformat () retorna uma sequência ISO 8601 local sem rotulá-la como local. Você precisa ter um datetime.timezone representando o fuso horário local para que o isoformat faça a coisa certa.
Sam Hartman

66

Aqui está o que eu uso para converter para o formato de data e hora XSD:

from datetime import datetime
datetime.now().replace(microsecond=0).isoformat()
# You get your ISO string

Me deparei com essa pergunta ao procurar o formato de data e hora XSD ( xs:dateTime). Eu precisava remover os microssegundos de isoformat.


4
O que é "XSD" (neste contexto)?
Peter Mortensen

1
Eu acredito que ele xs:datequis dizer com folhas de estilo XSD / XML.
sventechie

1
Isso significaxs:dateTime
radtek

56

Representação de tempo ISO 8601

A norma internacional ISO 8601 descreve uma representação de sequência para datas e horas. Dois exemplos simples desse formato são

2010-12-16 17:22:15
20101216T172215

(que significa 16 de dezembro de 2010), mas o formato também permite tempos de resolução de menos de um segundo e especificar fusos horários. Obviamente, esse formato não é específico para Python, mas é bom para armazenar datas e horas em um formato portátil. Detalhes sobre esse formato podem ser encontrados na entrada Markus Kuhn .

Eu recomendo o uso desse formato para armazenar horários em arquivos.

Uma maneira de obter o tempo atual nessa representação é usar o strftime do módulo de tempo na biblioteca padrão do Python:

>>> from time import strftime
>>> strftime("%Y-%m-%d %H:%M:%S")
'2010-03-03 21:16:45'

Você pode usar o construtor strptime da classe datetime:

>>> from datetime import datetime
>>> datetime.strptime("2010-06-04 21:08:12", "%Y-%m-%d %H:%M:%S")
datetime.datetime(2010, 6, 4, 21, 8, 12)

O mais robusto é o módulo Egenix mxDateTime:

>>> from mx.DateTime.ISO import ParseDateTimeUTC
>>> from datetime import datetime
>>> x = ParseDateTimeUTC("2010-06-04 21:08:12")
>>> datetime.fromtimestamp(x)
datetime.datetime(2010, 3, 6, 21, 8, 12)

Referências


2
Em que sentido é "mais robusto"?
Stéphane

Data:2018-05-25
loxaxs

Data e hora combinadas no UTC:2018-05-25T12:16:14+00:00
loxaxs

2
Data e hora combinadas no UTC:2018-05-25T12:16:14Z
loxaxs

Data e hora combinadas no UTC:20180525T121614Z
loxaxs

49

Encontrei o datetime.isoformat na documentação . Parece fazer o que você deseja:

datetime.isoformat([sep])

Return a string representing the date and time in ISO 8601 format, YYYY-MM-DDTHH:MM:SS.mmmmmm or, if microsecond is 0, YYYY-MM-DDTHH:MM:SS

If utcoffset() does not return None, a 6-character string is appended, giving the UTC offset in (signed) hours and minutes: YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or, if microsecond is 0 YYYY-MM-DDTHH:MM:SS+HH:MM

The optional argument sep (default 'T') is a one-character separator, placed between the date and time portions of the result. For example,
>>>

>>> from datetime import tzinfo, timedelta, datetime
>>> class TZ(tzinfo):
...     def utcoffset(self, dt): return timedelta(minutes=-399)
...
>>> datetime(2002, 12, 25, tzinfo=TZ()).isoformat(' ')
'2002-12-25 00:00:00-06:39'

30

A ISO 8601 permite uma representação compacta sem separadores, exceto o T, então eu gosto de usar essa linha única para obter uma sequência rápida de carimbo de data / hora:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%S.%fZ")
'20180905T140903.591680Z'

Se você não precisar dos microssegundos, deixe de fora a .%fparte:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
'20180905T140903Z'

Para hora local:

>>> datetime.datetime.now().strftime("%Y%m%dT%H%M%S")
'20180905T140903'

Editar:

Depois de ler um pouco mais sobre isso, recomendo que você deixe a pontuação. A RFC 3339 recomenda esse estilo porque, se todo mundo usa pontuação, não há risco de coisas como várias seqüências de caracteres ISO 8601 serem classificadas em grupos em sua pontuação. Portanto, o liner para uma cadeia de caracteres compatível seria:

>>> datetime.datetime.now().strftime("%Y-%m-%dT%H:%M%SZ")
'2018-09-05T14:09:03Z'

3
existe uma maneira de limitar os dígitos de milissegundos a 3? ou seja, meu outro aplicativo javascript produzirá 2019-02-23T04:02:04.051Zcom #new Date().toISOString()
Miranda Miranda

19

O formato de hora ISO 8601 não armazena um nome de fuso horário, apenas o deslocamento UTC correspondente é preservado.

Para converter um arquivo ctime em uma sequência de tempo ISO 8601, preservando o deslocamento UTC no Python 3:

>>> import os
>>> from datetime import datetime, timezone
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, timezone.utc)
>>> dt.astimezone().isoformat()
'2015-11-27T00:29:06.839600-05:00'

O código pressupõe que o fuso horário local é o Fuso Horário Oriental (ET) e que o sistema fornece um deslocamento UTC correto para o carimbo de data / hora POSIX fornecido (ts ), ou seja, o Python tem acesso a um banco de dados histórico de fuso horário no sistema ou no fuso horário. mesmas regras em uma determinada data.

Se você precisar de uma solução portátil; use o pytzmódulo que fornece acesso ao banco de dados tz :

>>> import os
>>> from datetime import datetime
>>> import pytz  # pip install pytz
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, pytz.timezone('America/New_York'))
>>> dt.isoformat()
'2015-11-27T00:29:06.839600-05:00'

O resultado é o mesmo neste caso.

Se você precisar do nome / abreviação / ID do fuso horário, armazene-o separadamente.

>>> dt.astimezone().strftime('%Y-%m-%d %H:%M:%S%z (%Z)')
'2015-11-27 00:29:06-0500 (EST)'

Nota: não, :no deslocamento UTC e na ESTabreviação do fuso horário não faz parte do formato de hora ISO 8601. Não é único.

Bibliotecas diferentes / versões diferentes da mesma biblioteca podem usar regras diferentes de fuso horário para a mesma data / fuso horário. Se for uma data futura, as regras ainda podem ser desconhecidas. Em outras palavras, o mesmo horário UTC pode corresponder a um horário local diferente, dependendo de quais regras você usa - salvar um horário no formato ISO 8601 preserva o horário UTC e o horário local que corresponde às regras de fuso horário atuais em uso na sua plataforma . Pode ser necessário recalcular a hora local em uma plataforma diferente se ela tiver regras diferentes.


14

Você precisará usar os.statpara obter o tempo de criação do arquivo e uma combinação de time.strftimee time.timezonepara formatação:

>>> import time
>>> import os
>>> t = os.stat('C:/Path/To/File.txt').st_ctime
>>> t = time.localtime(t)
>>> formatted = time.strftime('%Y-%m-%d %H:%M:%S', t)
>>> tz = str.format('{0:+06.2f}', float(time.timezone) / 3600)
>>> final = formatted + tz
>>> 
>>> final
'2008-11-24 14:46:08-02.00'

O fuso horário é responsável pelo horário de verão? Parece que tz será o mesmo, independentemente do horário de verão ou não.
Joseph Turian

2
Será qualquer deslocamento atualmente em vigor. Se o horário de verão estiver ativo, ele terá um deslocamento diferente do horário de verão.
Max Shawabkeh

4

Corrija-me se estiver errado (não estou), mas o deslocamento do UTC muda com o horário de verão. Então você deve usar

tz = str.format('{0:+06.2f}', float(time.altzone) / 3600)

Eu também acredito que o sinal deve ser diferente:

tz = str.format('{0:+06.2f}', -float(time.altzone) / 3600)

Eu posso estar errado, mas acho que não.


2

Concordo com Jarek e, além disso, observo que o caractere separador de deslocamento ISO é dois pontos, então acho que a resposta final deve ser:

isodate.datetime_isoformat(datetime.datetime.now()) + str.format('{0:+06.2f}', -float(time.timezone) / 3600).replace('.', ':')

2

Adicionando uma pequena variação à excelente resposta de estani

Local para ISO 8601 com TimeZone e sem informações de microssegundos (Python 3):

import datetime, time

utc_offset_sec = time.altzone if time.localtime().tm_isdst else time.timezone
utc_offset = datetime.timedelta(seconds=-utc_offset_sec)
datetime.datetime.now().replace(microsecond=0, tzinfo=datetime.timezone(offset=utc_offset)).isoformat()

Saída de amostra:

'2019-11-06T12:12:06-08:00'

Testou que essa saída pode ser analisada por Javascript Datee C # DateTime/DateTimeOffset


1

Eu desenvolvi esta função:

def iso_8601_format(dt):
    """YYYY-MM-DDThh:mm:ssTZD (1997-07-16T19:20:30-03:00)"""

    if dt is None:
        return ""

    fmt_datetime = dt.strftime('%Y-%m-%dT%H:%M:%S')
    tz = dt.utcoffset()
    if tz is None:
        fmt_timezone = "+00:00"
    else:
        fmt_timezone = str.format('{0:+06.2f}', float(tz.total_seconds() / 3600))

    return fmt_datetime + fmt_timezone

-6
import datetime, time    
def convert_enddate_to_seconds(self, ts):
    """Takes ISO 8601 format(string) and converts into epoch time."""
     dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+\
                datetime.timedelta(hours=int(ts[-5:-3]),
                minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
    seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
    return seconds 

>>> import datetime, time
>>> ts = '2012-09-30T15:31:50.262-08:00'
>>> dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+ datetime.timedelta(hours=int(ts[-5:-3]), minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
>>> seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
>>> seconds
1348990310.26
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.