Comment traduire une chaîne de caractères ISO 8601 datetime en un objet Python datetime? [dupliquer]
cette question a déjà une réponse ici:
j'obtiens une chaîne datetime dans un format comme "2009-05-28T16: 15: 00" (C'est ISO 8601, je crois) une option hack-ish semble être de parser la chaîne en utilisant time.strptime
et en passant les 6 premiers éléments du touple dans le constructeur datetime, comme:
datetime.datetime(*time.strptime("2007-03-04T21:08:12", "%Y-%m-%dT%H:%M:%S")[:6])
Je n'ai pas réussi à trouver une façon plus" propre " de faire ça, n'est-ce pas?
11 réponses
je préfère utiliser la bibliothèque dateutil pour la gestion du fuseau horaire et le parsing de date généralement solide. Si vous deviez obtenir une chaîne de caractères ISO 8601 comme: 2010-05-08T23:41:54.000 Z, vous vous amuseriez à la parcourir avec strptime, surtout si vous ne saviez pas à l'avance si le fuseau horaire était inclus ou non. pyiso8601 a quelques problèmes (vérifiez leur traceur) que j'ai rencontrés lors de mon utilisation et il n'a pas été mis à jour depuis quelques années. par contre, dateutil a été actif et a travaillé pour moi:
import dateutil.parser
yourdate = dateutil.parser.parse(datestring)
Avec Python 2.5:
datetime.datetime.strptime( "2007-03-04T21:08:12", "%Y-%m-%dT%H:%M:%S" )
parce que la norme ISO 8601 autorise de nombreuses variantes de couleurs et de tirets optionnels, essentiellement CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]
. Si vous voulez utiliser strptime, vous devez d'abord supprimer ces variantes.
le but est de générer un objet datetime utc.
Si vous voulez juste un cas de base qui fonctionne pour UTC avec le suffixe Z comme
2016-06-29T19:36:29.3453Z
:
datetime.datetime.strptime(timestamp.translate(None, ':-'), "%Y%m%dT%H%M%S.%fZ")
Si vous voulez gérer des décalages de fuseau horaire comme
2016-06-29T19:36:29.3453-0400
ou 2008-09-03T20:56:35.450686+05:00
utilisez ce qui suit. Ceux-ci convertiront toutes les variations en quelque chose sans délimiteurs de variables comme 20080903T205635.450686+0500
ce qui le rend plus cohérent/plus facile à analyser.
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" )
Si votre système ne supporte pas la directive
%z
strptime (vous voyez quelque chose comme ValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'
), alors vous devez décaler manuellement le temps de Z
(UTC). Note %z
peut ne pas fonctionner sur votre système en version python < 3 car il dépend du support de la bibliothèque c qui varie selon le type de construction système/python (par exemple 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
Flèche semble prometteur:
>>> import arrow
>>> arrow.get('2014-11-13T14:53:18.694072+00:00').datetime
datetime.datetime(2014, 11, 13, 14, 53, 18, 694072, tzinfo=tzoffset(None, 0))
Arrow est une bibliothèque Python qui fournit une manière intelligente de créer, de manipuler, de formater et de convertir des dates et des temps. Arrow est simple, léger et fortement inspiré par moment.js et demandes .
vous devez garder un oeil sur les informations du fuseau horaire, car vous pourriez avoir des problèmes lorsque vous comparez des datetimes Non-TZ-aware avec des TZ-aware.
C'est probablement le meilleur pour toujours tz-connaissance (même si seulement utc), à moins de vraiment savoir pourquoi il ne serait pas utile de le faire.
#-----------------------------------------------
import datetime
import pytz
import dateutil.parser
#-----------------------------------------------
utc = pytz.utc
BERLIN = pytz.timezone('Europe/Berlin')
#-----------------------------------------------
def to_iso8601(when=None, tz=BERLIN):
if not when:
when = datetime.datetime.now(tz)
if not when.tzinfo:
when = tz.localize(when)
_when = when.strftime("%Y-%m-%dT%H:%M:%S.%f%z")
return _when[:-8] + _when[-5:] # remove microseconds
#-----------------------------------------------
def from_iso8601(when=None, tz=BERLIN):
_when = dateutil.parser.parse(when)
if not _when.tzinfo:
_when = tz.localize(_when)
return _when
#-----------------------------------------------
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
inclut également le millisecondes et le fuseau horaire.
si le temps est '2012-09-30T15:31:50.262-08:00', cela se convertira en temps d'époque.
>>> 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
dans les deux sens:
d'une Époque à l'ISO du temps:
isoTime = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(epochTime))
ISO temps à l'Époque:
epochTime = time.mktime(time.strptime(isoTime, '%Y-%m-%dT%H:%M:%SZ'))
aniso8601 devrait gérer cela. Il comprend également timezones, python2 et python3, et a une couverture raisonnable du reste de ISO8601 si vous en avez besoin.
import aniso8601
aniso8601.parse_datetime('2007-03-04T21:08:12')
voici un souper façon simple de faire ce genre de conversions. Pas d'analyse, ou des bibliothèques supplémentaires requis. Propre, Simple, et Rapide.
import datetime
import time
################################################
#
# Takes the time (in seconds),
# and returns a string of the time in ISO8601 format.
# Note: Timezone is UTC
#
################################################
def TimeToISO8601(seconds):
strKv = datetime.datetime.fromtimestamp(seconds).strftime('%Y-%m-%d')
strKv = strKv + "T"
strKv = strKv + datetime.datetime.fromtimestamp(seconds).strftime('%H:%M:%S')
strKv = strKv +"Z"
return strKv
################################################
#
# Takes a string of the time in ISO8601 format,
# and returns the time (in seconds).
# Note: Timezone is UTC
#
################################################
def ISO8601ToTime(strISOTime):
K1 = 0
K2 = 9999999999
K3 = 0
counter = 0
while counter < 95:
K3 = (K1 + K2) / 2
strK4 = TimeToISO8601(K3)
if strK4 < strISOTime:
K1 = K3
if strK4 > strISOTime:
K2 = K3
counter = counter + 1
return K3
################################################
#
# Takes a string of the time in ISO8601 (UTC) format,
# and returns a python DateTime object.
# Note: returned value is your local time zone.
#
################################################
def ISO8601ToDateTime(strISOTime):
return time.gmtime(ISO8601ToTime(strISOTime))
#To test:
Test = "2014-09-27T12:05:06.9876"
print ("The test value is: " + Test)
Ans = ISO8601ToTime(Test)
print ("The answer in seconds is: " + str(Ans))
print ("And a Python datetime object is: " + str(ISO8601ToDateTime(Test)))