web-dev-qa-db-fra.com

Comment traduire une chaîne datetime ISO 8601 en un objet datetime Python?

Je reçois une chaîne de date/heure dans un format du type "2009-05-28T16: 15: 00" (ISO 8601, je crois). Une option intéressante semble consister à analyser la chaîne en utilisant time.strptime et à passer les six premiers éléments du Tuple dans le constructeur datetime, comme ceci:

datetime.datetime(*time.strptime("2007-03-04T21:08:12", "%Y-%m-%dT%H:%M:%S")[:6])

Je n'ai pas été capable de trouver un moyen "plus propre" de le faire. Est-ce qu'il y a un?

382
Andrey Fedorov

Je préfère utiliser la bibliothèque dateutil pour la gestion du fuseau horaire et l'analyse syntaxique généralement solide. Si vous obteniez une chaîne ISO 8601 telle que: 2010-05-08T23: 41: 54.000Z, vous auriez du plaisir à analyser cela 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 traqueur) que j'ai rencontrés au cours de mon utilisation et qui n'ont pas été mis à jour depuis quelques années. dateutil, en revanche, a été actif et a travaillé pour moi:

import dateutil.parser
yourdate = dateutil.parser.parse(datestring)
626
Wes Winham

Depuis Python 3.7 et aucune bibliothèque externe:

datetime.datetime.strptime('2019-01-04T16:41:24+0200', "%Y-%m-%dT%H:%M:%S%z")

Python 2 ne supporte pas le spécificateur de format %z, il est donc préférable d'utiliser explicitement l'heure zoulou partout si possible:

datetime.datetime.strptime("2007-03-04T21:08:12Z", "%Y-%m-%dT%H:%M:%SZ")
65
Philippe F

Étant donné que la norme ISO 8601 autorise de nombreuses variantes de la présence de deux points et de deux tirets facultatifs, fondamentalement CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]. Si vous souhaitez utiliser strptime, vous devez d’abord éliminer ces variations.

L'objectif 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 souhaitez gérer des décalages de fuseau horaire tels que 2016-06-29T19:36:29.3453-0400 ou 2008-09-03T20:56:35.450686+05:00, utilisez ce qui suit. Celles-ci convertiront toutes les variations en quelque chose sans délimiteurs de variables comme 20080903T205635.450686+0500 en le rendant 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 prend pas en charge 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'], vous devez décaler manuellement l'heure de Z (UTC). Remarque %z risque de ne pas fonctionner sur votre système avec Python versions <3 car cela dépend du support de la bibliothèque C, qui varie selon le type de construction système/Python (c'est-à-dire 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
48
theannouncer

Arrow semble prometteur pour cela:

>>> 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 offre un moyen judicieux et intelligent de créer, manipuler, formater et convertir des dates et des heures. Arrow est simple, léger et fortement inspiré par moment.js et requêtes .

38
Avi Flax

Vous devez garder un œil sur les informations du fuseau horaire, car vous pourriez avoir des problèmes lorsque vous comparez des dates/heures non compatibles avec tz avec des dates/heures compatibles avec tz.

Il est probablement préférable de toujours les avertir (même si c'est uniquement en UTC), à moins que vous ne sachiez vraiment 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
#-----------------------------------------------
16
Daniel F

Je ne l'ai pas encore essayé, mais pyiso8601 promet de le supporter.

8
Avi Flax
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

Cela inclut également les millisecondes et le fuseau horaire.

Si l'heure est '2012-09-30T15: 31: 50.262-08: 00', cela se convertira en heure de l'é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
6
ronak

Isodate semble avoir le support le plus complet.

6
Tobu

Dans les deux sens:

Époque au temps ISO:

isoTime = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(epochTime))

Temps ISO jusqu'à l'époque:

epochTime = time.mktime(time.strptime(isoTime, '%Y-%m-%dT%H:%M:%SZ'))
6
billmanH

aniso8601 devrait gérer cela. Il comprend également les fuseaux horaires, Python 2 et Python 3, et offre une couverture raisonnable du reste de ISO 8601 , si vous en avez besoin.

import aniso8601
aniso8601.parse_datetime('2007-03-04T21:08:12')
4
user3310495