今さらPython3 (70) - 日付時刻
第10章、日付とか時刻の扱い方の部分。
- 作者: Bill Lubanovic,斎藤康毅,長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/12/01
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
calendar
日付のフォーマットやタイムゾーンは悩ましい問題なのは確かで、ここではなぜか、isleap()で閏年判定が紹介されている。
>>> import calendar >>> calendar.isleap(1900) False >>> calendar.isleap(1996) True >>> calendar.isleap(1999) False >>> calendar.isleap(2000) True >>> calendar.isleap(2002) False >>> calendar.isleap(2016) True >>> calendar.isleap(2100) False >>>
何だっけ?西暦下二桁が4で割り切れる年は閏年。だけど、下二桁00の年は閏年でない。でも例外で上二桁が4で割りきれる場合は閏年になるみたいなルールだったよね。ま、上の通りです。
date
datetimeとdate両方があってなんでやねん!と思った事は確かに昔あったけど、ここから解説してくれるんだよねと期待して読み進む。
>>> from datetime import date >>> halloween = date(2015, 10, 31) >>> halloween datetime.date(2015, 10, 31) >>> halloween.day 31 >>> halloween.month 10 >>> halloween.year 2015 >>> halloween.isoformat() '2015-10-31'
まず、datetimeの中に、date, time, datetime, timedeltaという4つのメインオブジェクトがあるというところを押さえてからのdateを使ってますと。isoformat()以外は見たことも使ったこともあるかな。どこかの練習問題でstrftime()をゴニョゴニョして日付を表示させるたけど、それより簡単だね。
>>> from datetime import date >>> now = date.today() >>> now datetime.date(2015, 12, 27)
本日日付を出す場合は、date.today()が使える。それをnowに入れるから話がややこしくなるような。
>>> from datetime import timedelta >>> one_day = timedelta(days=1) >>> tomorrow = now + one_day >>> tomorrow datetime.date(2015, 12, 28) >>> now + 17 * one_day datetime.date(2016, 1, 13) >>> yesterday = now - one_day >>> yesterday datetime.date(2015, 12, 26)
じゃ、月とか年でもできるんだよね?
>|python|
>>> one_month = timedelta(months=1)
Traceback (most recent call last):
File "
TypeError: 'months' is an invalid keyword argument for this function
|
ダメなのかということで、ドキュメントを確認。
weeksはあるみたいなので、週でやってみよか。
>>> one_week = timedelta(weeks=1) >>> now + one_week datetime.date(2016, 1, 3) >>> now + one_week * 2 datetime.date(2016, 1, 10)
dateの許容範囲は9999/12/31までね。
timeとdatetime
>>> from datetime import time >>> noon = time(12,0,0) >>> noon datetime.time(12, 0) >>> noon.hour 12 >>> noon.minute 0 >>> noon.second 0 >>> noon.microsecond 0
timeはこんな感じ。dateとだいたい同じだけど、マイクロ秒まであるあたりは知っておいても良いかもね。
>>> from datetime import datetime >>> some_day = datetime(2016,1,2,3,4,5,6) >>> some_day datetime.datetime(2016, 1, 2, 3, 4, 5, 6) >>> some_day.isoformat() '2016-01-02T03:04:05.000006'
datetime()に引数を渡して日付+時刻を生成。isoformat()は日付だけじゃなくてdatetimeでも使える。
>>> from datetime import datetime >>> now = datetime.now() >>> now datetime.datetime(2015, 12, 27, 10, 55, 12, 680875) >>> now.year 2015 >>> now.month 12 >>> now.day 27 >>>
さっき、now使うとややこしくなるといったのはこれのこと。now()関数で現在のタイムスタンプをゲット。2月中旬のふりして、これ書いているのが年末だったりするけど。
>>> from datetime import datetime, time, date >>> noon = time(12) >>> this_day = date.today() >>> noon_today = datetime.combine(this_day, noon) >>> noon_today datetime.datetime(2015, 12, 27, 12, 0)
combine()でdate型とtime型を合体させてdatetime型に。
>>> noon_today.date() datetime.date(2015, 12, 27) >>> noon_today.time() datetime.time(12, 0)
これはその逆で、datetimeからdate, timeでそれぞれ取り出したところ。
datetimeの中にあるのとは別のtime
ややこしい。
>>> import time >>> now = time.time() >>> now 1451181661.426077 >>> time.ctime(now) 'Sun Dec 27 11:01:01 2015'
こっちのtimeは1970年1月1日0:00UTCを起点とする秒数表示ってことね。ctime()を使うと、ユーザフレンドリーなフォーマットで出てくる。
>>> time.localtime(now) time.struct_time(tm_year=2015, tm_mon=12, tm_mday=27, tm_hour=11, tm_min=1, tm_sec=1, tm_wday=6, tm_yday=361, tm_isdst=0) >>> time.gmtime(now) time.struct_time(tm_year=2015, tm_mon=12, tm_mday=27, tm_hour=2, tm_min=1, tm_sec=1, tm_wday=6, tm_yday=361, tm_isdst=0) >>> >>> tm = time.localtime(now) >>> time.mktime(tm) 1451181661.0 >>> tm.tm_year 2015 >>> tm.tm_min 1
localtime()とgmtime()でやると、ローカル時刻とUTCがそれぞれ取得できる。そこから逆にmktime()でUNIX時間に戻したり、各要素を取り出したり出来るんだね。
日時の読み書き
time.time()の復習から。
>>> import time >>> now = time.time() >>> time.ctime(now) 'Sun Dec 27 11:13:03 2015' >>>
こんどはstrftime()の出番だけど、指定子についてはこのリンクに書いてある。
8.1. datetime — 基本的な日付型および時間型 — Python 3.4.3 ドキュメント
>>> import time >>> fmt = "It's %A, %B, %d, %Y, local time %I:%M:%S%p" >>> t = time.localtime() >>> t time.struct_time(tm_year=2015, tm_mon=12, tm_mday=27, tm_hour=11, tm_min=16, tm_sec=52, tm_wday=6, tm_yday=361, tm_isdst=0) >>> time.strftime(fmt, t) "It's Sunday, December, 27, 2015, local time 11:16:52AM" >>>
これは、いつぞやの復習課題でやったパターンだね。
>>> from datetime import date >>> some_day = date(2015, 7, 4) >>> some_day.strftime(fmt) "It's Saturday, July, 04, 2015, local time 12:00:00AM" >>>
日付だけさっきのフォーマット(fmt)に放り込むと、時刻の部分は午前0時になる。ま、当たり前だね。
>>> from datetime import time >>> some_time = time(10,53) >>> some_time.strftime(fmt) "It's Monday, January, 01, 1900, local time 10:53:00AM" >>>
逆に時刻だけ入れたパターン。良かったのは1900年1月1日が月曜日だと分かったことぐらいかな?
>>> import time >>> fmt = "%Y-%m-%d" >>> time.strptime("2012 01 29", fmt) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/_strptime.py", line 494, in _strptime_time tt = _strptime(data_string, format)[0] File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/_strptime.py", line 337, in _strptime (data_string, format)) ValueError: time data '2012 01 29' does not match format '%Y-%m-%d' >>> time.strptime("2012-01-29", fmt) time.struct_time(tm_year=2012, tm_mon=1, tm_mday=29, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=29, tm_isdst=-1) >>>
逆に文字列の日付時刻を(システム的に)意味のある情報に変換するパターンはstrptime()を使うんだね。
>>> time.strptime("2012-13-29", fmt) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/_strptime.py", line 494, in _strptime_time tt = _strptime(data_string, format)[0] File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/_strptime.py", line 337, in _strptime (data_string, format)) ValueError: time data '2012-13-29' does not match format '%Y-%m-%d'
実存しない月とかを放り込むと怒られる。てか、そのぐらいのチェックはやるだろ普通。
>>> import locale >>> from datetime import date >>> halloween = date(2015, 10, 31) >>> for lang_country in ['en_us', 'fr_fr', 'de_de', 'es_es', 'is_is', 'ja_JP', 'zh_TW']: ... locale.setlocale(locale.LC_TIME, lang_country) ... halloween.strftime('%A, %B, %d') ... 'en_us' 'Saturday, October, 31' 'fr_fr' 'Samedi, octobre, 31' 'de_de' 'Samstag, Oktober, 31' 'es_es' 'sábado, octubre, 31' 'is_is' 'laugardagur, október, 31' 'ja_JP' '土曜日, 10月, 31' 'zh_TW' '周六, 10月, 31' >>>
setlocale()すると、指定したロケールで日付を返してくれると。最後に出ている中国語をどう指定するのかよく分からなかったけど、何やら方法があるらしい。
>>> import locale >>> names = locale.locale_alias.keys() >>> good_names = [name for name in names if \ ... len(name) == 5 and name[2] == '_'] >>> len(good_names) 251
locale.pyのソースコードを見たときに、zh_CHSというのがあったので、それを使おうと思ったらダメだった理由が分かった。5文字で真ん中に_があるやつだけが使えるんだね。
>>> ja_names = [name for name in names if name.startswith('ja')] >>> ja_names ['ja_jp.pck', 'ja_jp.mscode', 'ja', 'ja_jp', 'japan', 'japanese', 'ja_jp.euc', 'japanese-euc', 'japanese.euc'] >>> zh_names = [name for name in names if name.startswith('zh')] >>> zh_names ['zh_sg', 'zh_cn.euc', 'zh_tw.euc', 'zh_tw.euctw', 'zh_hk', 'zh_cn', 'zh_cn.big5', 'zh_tw', 'zh_hk.big5hk', 'zh', 'zh_sg.gbk']
これを見ると、日本語の場合はja_jpを使うしかなくて、中国語の場合はzh_sg, zh_hk, zh_cn, zh_twの中から選ぶ必要があるという事だね。
>>> for lang_country in ['zh_hk', 'zh_cn', 'zh_tw']: ... locale.setlocale(locale.LC_TIME, lang_country) ... halloween.strftime('%A, %B, %d') ... 'zh_hk' '周六, 10月, 31' 'zh_cn' '星期六, 十月, 31' 'zh_tw' '周六, 10月, 31' >>>
ちなみにzh_sgは指定してもエラーになったので削ってます。中国に以前住んでいたので、星期六の方がしっくりくるかな。(周とか礼拜も使うのは聞いたことあるけどね。)