Pythonでは日付を表す文字列からdatetime
型のオブジェクトへの変換にstrptime()を使用できる。
例えば'Thu Feb 11 17:01:34 2021'
という文字列があった場合、'%a %b %d %H:%M:%S %Y'
というフォーマット文字列を用意することでオブジェクトにできる。
なお、Ansibleの場合はto_datetime
フィルターでこの機能を使うこともできる。
ここで、タイムゾーンの表記と処理で少しハマったので備忘録。
- UTCオフセットによる表記 (例 +0900)
- タイムゾーン名表記 (例 JST)
- Dockerのpythonコンテナでタイムゾーン設定するには
- (おまけ) strptime()のフォーマット文字列抜粋
- 参考情報
UTCオフセットによる表記 (例 +0900
)
'Thu Feb 11 17:21:52 +0900 2021'
この表記の+0900
の部分は、小文字の%z
を使えば取得できる。
import datetime date_str_tz = 'Thu Feb 11 17:21:52 +0900 2021' format_str_tz = '%a %b %d %H:%M:%S %z %Y' dt_tz = datetime.datetime.strptime(date_str_tz, format_str_tz) print(dt_tz) print(dt_tz.tzinfo)
このコードを実行すると、結果は以下の通りでawareなオブジェクトとなる。
2021-02-11 17:21:52+09:00 UTC+09:00
ただしこのコードは、Python 3.6.9 では動作するが、Python 2.7.18 では%z
が対応しておらず以下のエラーで機能しない。
Traceback (most recent call last): File "strptime.py", line 18, in <module> dt_tz = datetime.datetime.strptime(date_str_tz, format_str_tz) File "/usr/local/lib/python2.7/_strptime.py", line 324, in _strptime (bad_directive, format)) ValueError: 'z' is a bad directive in format '%a %b %d %H:%M:%S %z %Y'
タイムゾーン名表記 (例 JST
)
'Thu Feb 11 17:07:53 JST 2021'
この表記のJST
の部分は、大文字の%Z
を使えば取得できる。
date_str_tz = 'Thu Feb 11 17:07:53 JST 2021' format_str_tz = '%a %b %d %H:%M:%S %Z %Y' dt_tz = datetime.datetime.strptime(date_str_tz, format_str_tz) print(dt_tz) print(dt_tz.tzinfo) # None
実行すると以下の通り。
%z
の場合と異なりtzinfoはNoneとなっている。
2021-02-11 17:07:53 None
ただしこの%Z
を使ったタイムゾーン名の書式指定は、実行環境であるOSのタイムゾーン設定に依存しており、GMT
とUTC
以外のタイムゾーンについてはOSの設定と合致していないとエラーになってしまう。
例えばpython:3
Dockerイメージのように、OSのタイムゾーンが設定されておらずUTC
のまま(シェル上でdate
実行などで確認できる)の場合は、以下のようにエラーとなる。
Traceback (most recent call last): File "/tmp/strptime.py", line 12, in <module> dt_tz = datetime.datetime.strptime(date_str_tz, format_str_tz) File "/usr/local/lib/python3.9/_strptime.py", line 568, in _strptime_datetime tt, fraction, gmtoff_fraction = _strptime(data_string, format) File "/usr/local/lib/python3.9/_strptime.py", line 349, in _strptime raise ValueError("time data %r does not match format %r" % ValueError: time data 'Thu Feb 11 17:07:53 JST 2021' does not match format '%a %b %d %H:%M:%S %Z %Y'
該当ドキュメントは以下の通り。(日本語版でも訳されてないけどなぜかどの言語もJST
と日本に住んでる人に向けた例文になっているw)
%Z
In strftime(),
%Z
is replaced by an empty string if tzname() returnsNone
; otherwise%Z
is replaced by the returned value, which must be a string. strptime() only accepts certain values for%Z
:
- any value in
time.tzname
for your machine's locale- the hard-coded values
UTC
andGMT
So someone living in Japan may have
JST
,UTC
, andGMT
as valid values, but probably notEST
. It will raiseValueError
for invalid values.
例えばEST
というタイムゾーン名(東部標準時)の場合は、OSのタイムゾーン設定もESTになっている必要がある。
$ docker run --rm -v "$PWD":/mnt -e TZ=America/New_York -it python:3 bash root@4e1469a8fd52:/# date Thu Feb 11 08:09:23 EST 2021 root@4e1469a8fd52:/# python Python 3.9.1 (default, Feb 9 2021, 07:42:03) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import datetime >>> date_str_tz = 'Thu Feb 11 17:07:53 JST 2021' >>> format_str_tz = '%a %b %d %H:%M:%S %Z %Y' >>> dt_tz = datetime.datetime.strptime(date_str_tz, format_str_tz) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.9/_strptime.py", line 568, in _strptime_datetime tt, fraction, gmtoff_fraction = _strptime(data_string, format) File "/usr/local/lib/python3.9/_strptime.py", line 349, in _strptime raise ValueError("time data %r does not match format %r" % ValueError: time data 'Thu Feb 11 17:07:53 JST 2021' does not match format '%a %b %d %H:%M:%S %Z %Y' >>> print(dt_tz) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'dt_tz' is not defined
上記の通り、OS設定がESTになっていると,JST
の文字列は解析失敗している。
この状態からEST
である文字列を処理すると以下の通り。
>>> date_str_tz = 'Thu Feb 11 17:07:53 EST 2021' >>> dt_tz = datetime.datetime.strptime(date_str_tz, format_str_tz) >>> print(dt_tz) 2021-02-11 17:07:53 >>> print(dt_tz.tzinfo) None
この通り、EST
というタイムゾーン名を処理できている。
なお、タイムゾーン名がGMT
あるいはUTC
であれば、OSのタイムゾーンには関係せず、Python 2.7.18 でも動作確認。
$ docker run --rm -v "$PWD":/mnt -it python:2 bash root@2bd09566c12f:/# python Python 2.7.18 (default, Apr 20 2020, 19:27:10) [GCC 8.3.0] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import datetime >>> date_str_tz = 'Thu Feb 11 17:07:53 UTC 2021' >>> format_str_tz = '%a %b %d %H:%M:%S %Z %Y' >>> dt_tz = datetime.datetime.strptime(date_str_tz, format_str_tz) >>> dt_tz datetime.datetime(2021, 2, 11, 17, 7, 53) >>> dt_tz.tzinfo >>> print(dt_tz.tzinfo) None
Dockerのpython
コンテナでタイムゾーン設定するには
-e TZ=Asia/Tokyo
を付与する。
※ これはpython
コンテナイメージ(baseがdebian)の場合。CentOS系も同様。ただしAlpineはまた別
[zaki@cloud-dev ~]$ docker run --rm -v "$PWD":/mnt -e TZ=Asia/Tokyo -it python:3 bash root@d8719dc21019:/# date Thu Feb 11 22:47:17 JST 2021
(おまけ) strptime()のフォーマット文字列抜粋
頻出
指定子 | 意味 |
---|---|
%Y |
西暦 (4桁) |
%m |
月 (01 オリジン) |
%d |
日 |
%H |
時 |
%M |
分 |
%S |
秒 |
マイナー(個人の感想)な表記
指定子 | 意味 |
---|---|
%a |
曜日の英語表記(Mon. とかfri とか) |
%b |
月の英語表記(Feb とかmay とか) |
%f |
マイクロ秒(秒の小数点未満6桁) |
%I |
12時間表記のhour (↓とセットで使う) |
%p |
AM/PM (↑とセットで使う) |
%Z |
タイムゾーン名 (UTC とかGMT とかJST とか。本記事参照) |
%z |
UTCオフセット |
ドキュメントには「ロケールの曜日名」とか書かれているが、試した限りja_JP.UTF-8
設定の環境でも「水
」とかは認識しなかった。