85 votes

Comment analyser les dates avec -0400 fuseau horaire chaîne de caractères en python?

J'ai une date en chaîne de la forme '2009/05/13 19:19:30 -0400'. Il semble que les précédentes versions de python peut avoir pris en charge un %z format de balise dans strptime pour la fin de fuseau horaire cahier des charges, mais 2.6.x semble avoir enlevé.

Quelle est la bonne façon de convertir cette chaîne en un objet datetime?

125voto

txwikinger Points 1794

Vous pouvez utiliser la fonction d'analyse de dateutil:

>>> from dateutil.parser import parse
>>> d = parse('2009/05/13 19:19:30 -0400')
>>> d
datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=tzoffset(None, -14400))

De cette façon, vous obtenez un objet datetime vous pouvez ensuite utiliser.

Mise à JOUR: Comme répondu dateutil2.0 est écrit pour python3.0 et ne fonctionne pas avec python2.x. Pour python2.x dateutil1.5 doit être utilisé.

54voto

J.F. Sebastian Points 102961

%z est pris en charge en Python 3.2+:

>>> from datetime import datetime
>>> datetime.strptime('2009/05/13 19:19:30 -0400', '%Y/%m/%d %H:%M:%S %z')
datetime.datetime(2009, 5, 13, 19, 19, 30,
                  tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))

Sur les versions antérieures:

from datetime import datetime

date_str = '2009/05/13 19:19:30 -0400'
naive_date_str, _, offset_str = date_str.rpartition(' ')
naive_dt = datetime.strptime(naive_date_str, '%Y/%m/%d %H:%M:%S')
offset = int(offset_str[:3])*60 + int(offset_str[-2:])
dt = naive_dt.replace(tzinfo=FixedOffset(offset))
print(repr(dt))
# -> datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=FixedOffset(-240))
print(dt)
# -> 2009-05-13 19:19:30-04:00

FixedOffset est une classe basée sur l'exemple de code à partir de la documentation:

from datetime import timedelta, tzinfo

class FixedOffset(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)

7voto

sayap Points 2130

Le problème avec l'aide de dateutil est que vous ne pouvez pas avoir la même chaîne de format pour les deux la sérialisation et la désérialisation, comme dateutil a limité les options de mise en forme (seulement dayfirst et yearfirst).

Dans mon application, je stocke la chaîne de format dans .Fichier INI, et chaque déploiement peut avoir son propre format. Ainsi, je n'aime vraiment pas le dateutil approche.

Voici une autre méthode qui utilise pytz à la place:

from datetime import datetime, timedelta

from pytz import timezone, utc
from pytz.tzinfo import StaticTzInfo

class OffsetTime(StaticTzInfo):
    def __init__(self, offset):
        """A dumb timezone based on offset such as +0530, -0600, etc.
        """
        hours = int(offset[:3])
        minutes = int(offset[0] + offset[3:])
        self._utcoffset = timedelta(hours=hours, minutes=minutes)

def load_datetime(value, format):
    if format.endswith('%z'):
        format = format[:-2]
        offset = value[-5:]
        value = value[:-5]
        return OffsetTime(offset).localize(datetime.strptime(value, format))

    return datetime.strptime(value, format)

def dump_datetime(value, format):
    return value.strftime(format)

value = '2009/05/13 19:19:30 -0400'
format = '%Y/%m/%d %H:%M:%S %z'

assert dump_datetime(load_datetime(value, format), format) == value
assert datetime(2009, 5, 13, 23, 19, 30, tzinfo=utc) \
    .astimezone(timezone('US/Eastern')) == load_datetime(value, format)

3voto

geofflane Points 1845

Réponse courte est qu'il ne fonctionne pas. Plus de réponse, vous devriez voir la réponse à cette question: python le temps de l'âge de la partie 2, fuseaux horaires

-10voto

Gyom Points 1004

Si vous êtes sous linux, vous pouvez utiliser l'externe date commande pour dwim :

import commands, datetime

def parsedate(text):
  output=commands.getoutput('date -d "%s" +%%s' % text )
  try:
      stamp=eval(output)
  except:
      print output
      raise
  return datetime.datetime.frometimestamp(stamp)

Bien sûr, cela est moins portable que dateutil, mais un peu plus souple, car date également accepter des entrées comme "hier" ou "l'année dernière" :-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X