change - strftime python
¿Cómo se analizan las fechas con una cadena de zona horaria de-0400 en Python? (6)
Tengo una cadena de fecha del formulario ''2009/05/13 19:19:30 -0400''. Parece que las versiones anteriores de Python pueden haber admitido una etiqueta de formato% z en strptime para la especificación de zona horaria posterior, pero 2.6.x parece haber eliminado eso.
¿Cuál es la forma correcta de analizar esta cadena en un objeto datetime?
Aquí hay una solución al problema de "%z"
para Python 2.7 y versiones anteriores
En lugar de usar:
datetime.strptime(t,''%Y-%m-%dT%H:%M %z'')
Usa el timedelta
para tener en cuenta la zona horaria, así:
from datetime import datetime,timedelta
def dt_parse(t):
ret = datetime.strptime(t[0:16],''%Y-%m-%dT%H:%M'')
if t[18]==''+'':
ret-=timedelta(hours=int(t[19:22]),minutes=int(t[23:]))
elif t[18]==''-'':
ret+=timedelta(hours=int(t[19:22]),minutes=int(t[23:]))
return ret
Tenga en cuenta que las fechas se convertirían a GMT
, lo que permitiría hacer aritmética de fecha sin preocuparse por las zonas horarias.
El problema con el uso de dateutil es que no se puede tener la misma cadena de formato tanto para la serialización como para la deserialización, ya que dateutil tiene opciones de formato limitadas (solo el dayfirst
y el yearfirst
).
En mi aplicación, almaceno la cadena de formato en el archivo .INI, y cada implementación puede tener su propio formato. Por lo tanto, realmente no me gusta el enfoque dateutil.
Aquí hay un método alternativo que usa pytz en su lugar:
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)
Puede usar la función de análisis 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 esta forma, obtienes un objeto datetime que puedes usar.
Como se answered , dateutil2.0 está escrito para Python 3.0 y no funciona con Python 2.x. Para Python 2.x se necesita usar dateutil1.5.
Si está en Linux, puede usar el comando de date
externo para 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)
Esto es, por supuesto, menos portátil que dateutil, pero un poco más flexible, porque la date
también aceptará entradas como "ayer" o "el año pasado" :-)
Un trazador de líneas para los viejos pitones hacia fuera allí. Puedes multiplicar un timedelta por 1 / -1 dependiendo de +/- signo, como en:
datetime.strptime(s[:19], ''%Y-%m-%dT%H:%M:%S'') + timedelta(hours=int(s[20:22]), minutes=int(s[23:])) * (-1 if s[19] == ''+'' else 1)
%z
es compatible con 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)))
En versiones anteriores:
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[-4:-2])*60 + int(offset_str[-2:])
if offset_str[0] == "-":
offset = -offset
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
donde FixedOffset
es una clase basada en el ejemplo de código de los documentos :
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)