'2009/05/13 19:19:30-0400'という形式の日付文字列があります。以前のバージョンのPythonは、後続のタイムゾーン仕様のstrptimeで%z形式のタグをサポートしていたようですが、2.6.xではそれが削除されたようです。
この文字列を日時オブジェクトに解析する正しい方法は何ですか?
回答:
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))
このようにして、使用できる日時オブジェクトを取得します。
回答済みのとおり、dateutil2.0はPython 3.0用に作成されており、Python2.xでは機能しません。Python 2.xの場合、dateutil1.5を使用する必要があります。
%z
Python3.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)))
以前のバージョンの場合:
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
ここFixedOffset
に基づいてクラスであるドキュメントからのコードの例は:
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)
ValueError: 'z' is a bad directive in format '%Y-%m-%d %M:%H:%S.%f %z'
私の場合(Python 2.7)が発生します。
"%z"
Python2.7以前の問題の修正は次のとおりです
使用する代わりに:
datetime.strptime(t,'%Y-%m-%dT%H:%M %z')
次のように、timedelta
を使用してタイムゾーンを説明します。
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
日付はに変換されることに注意してくださいGMT
。これにより、タイムゾーンを気にせずに日付の計算を実行できます。
+
はtimedeltaをしなければならない文字引き算、およびその逆。コードを編集して修正しました。
dateutilを使用しての問題はdateutilはオプション(のみの書式限られているあなたは、シリアライズとデシリアライズの両方に同じフォーマット文字列を持つことができないということであるdayfirst
とyearfirst
)。
私のアプリケーションでは、フォーマット文字列を.INIファイルに保存し、各デプロイメントは独自のフォーマットを持つことができます。したがって、私はdateutilアプローチが本当に好きではありません。
代わりにpytzを使用する別の方法を次に示します。
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)
Linuxを使用している場合は、外部date
コマンドを使用して次のように操作できます。
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)
もちろん、これはdateutilよりも移植性が低くなりますが、date
「昨日」や「昨年」などの入力も受け入れるため、少し柔軟性があります:-)
dateutil
、Pythonを使用する私(2.1)では問題なく機能し2.7.2
ます。Python3は必要ありません。pipからインストールする場合、パッケージ名はpython-dateutil
。であることに注意してください。