ようこそゲストさん

mitc - 日記

2011/03/30(水) python-dateutilを使ってみる

はてブ 2011/03/30 11:24 Pythonmiff

はじめに

OSWindows 7 SP1
Python2.7
dateutil1.5
 以前にPythonのタイムゾーン変換(UTC->JST)ではまったという記事を書きましたが,その記事でpython-dateutilというモジュールを使うと便利だというコメントを頂いたので試してみました.

モジュールの概要

python-dateutil
  • 標準のdatetimeモジュールを強力に拡張した日付処理モジュール.
  • Python2.3以上で動作
    • Python2.Xではdateutil 1.X(PSF License)
    • Python3.Xではdateutil 2.X(Simplified BSD License)
 「来月」,「次の月曜日」や「月末の週」のような日時の相対的な計算,様々な日付文字列への対応,そしてTimezoneへの対応などで日時の処理を便利にしてくれるようです.詳しくは公式のリファレンスを参照して下さい.

インストール

 setup.pyを使うか配布アーカイブに同梱されているdateutilフォルダをそのままモジュールとして使います.

配布アーカイブの同梱物
配布アーカイブの同梱物

モジュールの使用例
モジュールの使用例

タイムゾーン変換

 dateutilには標準でUTCのタイムゾーン情報がdateutil.tz.tzutc()として定義されているので,以前のエントリで書いたコードを次のように書き換えられます.わざわざUTCから変換するのにクラスを書かなければならない不合理を解消できますね.

tzlocal:システムローカルのタイムゾーン
import datetime
import dateutil.tz

def _main():
    dt = datetime.datetime.strptime("Wed Mar 30 01:16:33 +0000 2011", "%a %b %d %H:%M:%S +0000 %Y")
    dt = dt.replace(tzinfo=dateutil.tz.tzutc()).astimezone(dateutil.tz.tzlocal())

if __name__ == '__main__':
    _main()
tz.gettz:タイムゾーンをファイルから読み込む
import datetime
import dateutil.tz

def _main():
    dt = datetime.datetime.strptime("Wed Mar 30 01:16:33 +0000 2011", "%a %b %d %H:%M:%S +0000 %Y")
    dt = dt.replace(tzinfo=dateutil.tz.tzutc()).astimezone(dateutil.tz.gettz('Asia/Tokyo'))

if __name__ == '__main__':
    _main()
zoneinfo.gettz:タイムゾーンをファイルから読み込む
import dateutil.zoneinfo

def _main():
    dt = datetime.datetime.strptime("Wed Mar 30 01:16:33 +0000 2011", "%a %b %d %H:%M:%S +0000 %Y")
    dt = dt.replace(tzinfo=dateutil.tz.tzutc()).astimezone(dateutil.zoneinfo.gettz("Asia/Tokyo"))

if __name__ == '__main__':
    _main()
 JSTのタイムゾーン情報を取得するのに使用しているtz.gettzとzoneinfo.gettzの違いはいまいちわかりません.ソースコードを見るとtz.gettzは色々と条件判断しながらよしなにしてくれるのに対してzoneinfo.gettzは必ずdateutil/zoneinfoに含まれるzoneinfo-*.tar.gzからタイムゾーン情報を読み込むようです*1

 更に,dateutilの日付文字列解析機能を使うとコードはもっと簡単になります.
import dateutil.parser

def _main():
    dt = dateutil.parser.parse("Wed Mar 30 01:16:33 +0000 2011")
    dt = dt.replace(tzinfo=dateutil.tz.tzutc()).astimezone(dateutil.tz.tzlocal())

if __name__ == '__main__':
    _main()

*1 : tz.gettzも特に設定しないまま使うとzoneinfo.gettzと同じ動きになるようだ?

その他

 タイムゾーン変換をちょっと楽にするためだけに新たなモジュールを入れるなんて……という新たな不合理に対しては,タイムゾーン変換以外の機能も使ってみるというのはどうでしょう.relativedeltaを使うだけで日時の計算が色々と便利になりそうです.
#-*- coding: utf-8 -*-
from datetime import *
from dateutil.relativedelta import *
import calendar

def _main():
    now = datetime.now()
    today = date.today()
    # 来月
    print now + relativedelta(months=+1)
    # 来月の次の週
    print now + relativedelta(months=+1, weeks=+1)
    # 来月の次の週のAM10時
    print now + relativedelta(months=+1, weeks=+1, hour=10)
    # datetimeだけでなくdateも使用可能
    print relativedelta(datetime(2003,10,24,10,0), today)
    # 一ヶ月前の一年後
    print now + relativedelta(years=+1, months=-1)
    # 次の金曜日
    print today + relativedelta(weekday=FR)
    print today + relativedelta(weekday=calendar.FRIDAY)
    # 今月の最後の金曜日
    print today + relativedelta(day=31, weekday=FR(-1))
    # 次の水曜日
    print today + relativedelta(weekday=WE(+1))
    # 今日以降の次の水曜日(「今日」が水曜日の場合に上の方法では「今日」が算出されるため)
    print today + relativedelta(days=+1, weekday=WE(+1))
    # 次の1000年期までどれだけかかるか
    print relativedelta(now, date(3001,1,1))
    # 次の世紀までどれだけかかるか
    print relativedelta(now, date(2101,1,1))
    # 1980年5月3日生まれの人は今何歳か
    print relativedelta(now, date(1980,5,3)).years

if __name__ == '__main__':
    _main()


名前:  非公開コメント   

E-Mail(任意/非公開):
URL(任意):
  • TB-URL  http://mitc.s279.xrea.com/adiary.cgi/0100/tb/