Tempo ISO (ISO 8601) in Python


340

Ho un file In Python, vorrei prendere il suo tempo di creazione e convertirlo in una stringa ISO time (ISO 8601) preservando il fatto che è stato creato nel fuso orario orientale (ET) .

Come posso prendere il ctime del file e convertirlo in una stringa ISO che indica il fuso orario orientale (e tiene conto dell'ora legale, se necessario)?



11
@ Nick- Link utile, ma non un duplicato- sta chiedendo di convertire in altro modo.
Yarin,

1
@ Joseph- Ho appena chiesto questo riguardo a RFC 3999- dovrebbe funzionare per questo - Genera timestamp RFC 3339 in Python
Yarin,

Risposte:


560

Locale secondo ISO 8601:

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

UTC secondo ISO 8601:

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

Locale secondo ISO 8601 senza microsecondi:

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

UTC secondo ISO 8601 con informazioni TimeZone (Python 3):

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

UTC secondo ISO 8601 con informazioni sul fuso orario locale senza microsecondi (Python 3):

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

Locale secondo ISO 8601 con informazioni TimeZone (Python 3):

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

Si noti che esiste un bug quando si utilizza astimezone()in tempo utc. Questo dà un risultato errato:

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

Per Python 2, vedi e usa pytz .


17
.isoformat()può prendere un parametro di separazione, (nel caso in cui si desideri qualcosa di diverso da 'T'):.isoformat(' ')
ThorSummoner

5
@ThorSummoner buono a sapersi! Ma fai attenzione che cambiare il separatore non sia più conforme alla ISO-8601 ... il che ha poco senso (inoltre, ci sono modi migliori per stampare le date ma non è questa la domanda qui). RFC
estani,

4
Lo spazio è consentito come parte dello standard ISO-8601. It is permitted to omit the 'T' character by mutual agreement.
Raychi,

4
@raychi È sempre permesso cambiare uno standard di comune accordo (che in molti casi infrange lo standard, ma a chi importa se si tratta di un accordo reciproco, giusto?). Il mio 2c: basta, lascialo così com'è.
estani,

14
Questa risposta è errata perché datetime.datetime.now (). Isoformat () restituisce una stringa ISO 8601 locale senza etichettarla come locale. Devi avere un datetime.timezone che rappresenta il fuso orario locale per ottenere che isoformat faccia la cosa giusta.
Sam Hartman,

66

Ecco cosa uso per convertire nel formato datetime XSD:

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

Mi sono imbattuto in questa domanda quando ho cercato il formato ora XSD ( xs:dateTime). Avevo bisogno di rimuovere i microsecondi da isoformat.


4
Che cos'è "XSD" (in questo contesto)?
Peter Mortensen,

1
Credo che intenda xs:datedai fogli di stile XSD / XML.
sventechie,

1
Significaxs:dateTime
radtek,

56

Rappresentazione temporale ISO 8601

Lo standard internazionale ISO 8601 descrive una rappresentazione di stringa per date e orari. Sono due semplici esempi di questo formato

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

(che rappresentano entrambi il 16 dicembre 2010), ma il formato consente anche tempi di risoluzione inferiori al secondo e specificare i fusi orari. Questo formato non è ovviamente specifico per Python, ma è utile per memorizzare date e orari in un formato portatile. I dettagli su questo formato sono disponibili nella voce Markus Kuhn .

Consiglio di utilizzare questo formato per memorizzare i tempi nei file.

Un modo per ottenere l'ora corrente in questa rappresentazione è usare strftime dal modulo time nella libreria standard di Python:

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

È possibile utilizzare il costruttore strptime della 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)

Il più robusto è il modulo 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)

Riferimenti


2
In che senso è "più robusto"?
Stéphane,

Data:2018-05-25
loxaxs

Data e ora combinate in UTC:2018-05-25T12:16:14+00:00
loxaxs

2
Data e ora combinate in UTC:2018-05-25T12:16:14Z
loxaxs

Data e ora combinate in UTC:20180525T121614Z
loxaxs

49

Ho trovato il datetime.isoformat nella documentazione . Sembra fare quello che vuoi:

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

ISO 8601 consente una rappresentazione compatta senza separatori ad eccezione di T, quindi mi piace usare questo one-liner per ottenere una stringa timestamp veloce:

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

Se non hai bisogno dei microsecondi, lascia fuori la .%fparte:

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

Per l'ora locale:

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

Modificare:

Dopo aver letto di più su questo, ti consiglio di lasciare la punteggiatura. RFC 3339 raccomanda questo stile perché se tutti usano la punteggiatura, non c'è il rischio che cose come più stringhe ISO 8601 vengano ordinate in gruppi sulla loro punteggiatura. Quindi l'unico liner per una stringa conforme sarebbe:

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

3
c'è un modo per limitare le cifre dei millisecondi a 3? cioè la mia altra app javascript produrrà 2019-02-23T04:02:04.051Zconnew Date().toISOString()
Miranda,

19

Il formato dell'ora ISO 8601 non memorizza il nome di un fuso orario, viene conservato solo l'offset UTC corrispondente.

Per convertire un file ctime in una stringa temporale ISO 8601 mantenendo l'offset UTC in 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'

Il codice presuppone che il fuso orario locale sia fuso orario orientale (ET) e che il sistema fornisca un offset UTC corretto per il dato timestamp POSIX ( ts), ovvero Python abbia accesso a un database di fuso orario storico sul sistema o che il fuso orario avesse il stesse regole a una determinata data.

Se hai bisogno di una soluzione portatile; utilizzare il pytzmodulo che fornisce l'accesso al database 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'

Il risultato è lo stesso in questo caso.

Se è necessario il nome del fuso orario / abbreviazione / ID zona, memorizzarlo separatamente.

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

Nota: no, :nell'offset UTC e l' ESTabbreviazione del fuso orario non fa parte del formato orario ISO 8601. Non è unico.

Librerie diverse / versioni diverse della stessa libreria possono utilizzare regole di fuso orario diverse per la stessa data / fuso orario. Se è una data futura, le regole potrebbero essere ancora sconosciute. In altre parole, la stessa ora UTC può corrispondere a un'ora locale diversa a seconda delle regole utilizzate: il salvataggio di un'ora nel formato ISO 8601 preserva l'ora UTC e l'ora locale che corrisponde alle regole del fuso orario attualmente in uso sulla piattaforma . Potrebbe essere necessario ricalcolare l'ora locale su una piattaforma diversa se ha regole diverse.


14

Dovrai utilizzare os.statper ottenere il tempo di creazione del file e una combinazione di time.strftimee time.timezoneper la formattazione:

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

Il fuso orario rappresenta l'ora legale? Sembra che tz sarà lo stesso indipendentemente dall'ora legale o meno.
Joseph Turian,

2
Sarà qualsiasi offset attualmente in vigore. Se l'ora legale è attiva, avrà un offset diverso da quando l'ora legale non lo è.
Max Shawabkeh,

4

Correggimi se sbaglio (non lo sono), ma l'offset da UTC cambia con l'ora legale. Quindi dovresti usare

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

Credo anche che il segno dovrebbe essere diverso:

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

Potrei sbagliarmi, ma non la penso così.


2

Sono d'accordo con Jarek e noto inoltre che il carattere separatore offset ISO è un due punti, quindi penso che la risposta finale dovrebbe essere:

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

2

Aggiungendo una piccola variazione all'ottima risposta di estani

Locale secondo ISO 8601 con TimeZone e nessuna informazione sui microsecondi (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()

Uscita campione:

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

Testato che questo output può essere analizzato sia da Javascript Dateche da C # DateTime/DateTimeOffset


1

Ho sviluppato questa funzione:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.