4
2

More than 5 years have passed since last update.

PythonでUNIXタイム(POSIXタイム)とタイムゾーン

Last updated at Posted at 2018-12-22

概要

Pythonで時刻を扱う際にはdatetimeモジュールを使うのが一般的。Python3でも少し前までは、UNIXタイムを扱うのに一手間かかったが、Python3.7ではとても扱いやすくなっている。

datetimeオブジェクトに対してtimestamp()でUNIXタイムを取得することができ、 datetime.fromtimestamp()(classmethod)でUNIXタイムからdatetimeオブジェクトを作ることができる。

気軽にUNIXタイムを扱えるのは嬉しいが、タイムゾーンに気にしないと、意図しない結果になることがある。

環境

Pythonのバージョンは3.7を使用する。macOSで動作を確認した。

UNIXタイムとは

説明不要だと思うが、ウィキペディアから念の為引用しておく。

UNIX時間(ユニックスじかん)またはUNIX時刻(ユニックスじこく、UNIX time(ユニックスタイム)、POSIX time(ポジックスタイム))とはコンピューターシステム上での時刻表現の一種。UNIXエポック、すなわち協定世界時 (UTC) での1970年1月1日午前0時0分0秒から形式的な経過秒数(すなわち、実質的な経過秒数から、その間に挿入された閏秒を引き、削除された閏秒を加えたもの)として表される。

個人的に想定外だった挙動

>>> from datetime import datetime
>>> datetime.fromtimestamp(0)
datetime.datetime(1970, 1, 1, 9, 0)

"1970/01/01 00:00:00"を期待していたら、9時間ずれていた。お察しの通り、日本標準時(UTC+9)が関係している。

仕様です

ドキュメントには、datetime.fromtimestamp(timestamp, tz=None)について次のように書いてある。

POSIX タイムスタンプに対応するローカルな日付と時刻を返します。オプションの引数 tz が None であるか、指定されていない場合、タイムスタンプはプラットフォームのローカルな日付および時刻に変換され、返される datetime オブジェクトは naive なものになります。

POSIX タイムスタンプに対応するローカルな日付と時刻を返します 」ということで、ローカルな時刻(今回はJST)の時刻が返された。引用中の「naiveなもの」については、後述する。

UTCの時刻情報がほしい時は、datetime.utcfromtimestamp(timestamp)のほうを使えばよかった。

>>> datetime.utcfromtimestamp(0)
datetime.datetime(1970, 1, 1, 0, 0)

また、fromtimestamp()にはタイムゾーンの情報が渡せるので、そちらの方法で対応することもできる。

>>> from datetime import datetime, timezone
>>> datetime.fromtimestamp(0, timezone.utc)
datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)

tzinfoが追加されたが、同じっぽい結果が得られた。このtzinfoが何かを知ろうと思うと、"naive" と "aware"の2種類のオブジェクトについて理解する必要がある。

"naive" と "aware"

datetimeモジュールで扱う時刻オブジェクトは、"naive"と"aware"の2種類に区別される。
簡単にいうと、"naive"はタイムゾーンに関する情報を持たず、"aware"はタイムゾーンに関する情報を持つ時刻オブジェクトを指す。

それぞれのメリット、デメリットについては公式ドキュメントを読むとよい。

オブジェクトの作成時にタイムゾーンの情報を渡せばawareなオブジェクトを得られるし、そうでなければnaiveになると覚えておけば、基本的に問題ないと思われる。

先ほどの例でいうと、datetime.fromtimestamp(0)ではnaiveなオブジェクトが生成され、datetime.fromtimestamp(0, timezone.utc)ではawareなオブジェクトが生成された。

awareなオブジェクトの作り方

datetimeモジュールでは、タイムゾーンを表すためにtzinfoのサブクラスが使われる。このサブクラスを自分で実装することもできるが、dateutilもしくはpytzというライブラリがよく使われている。

例えば、dateutilを使うと次のようになる。

>>> from datetime import datetime
>>> from dateutil import tz
>>> datetime.now(tz=tz.gettz("Asia/Tokyo"))
datetime.datetime(2018, 12, 22, 23, 20, 56, 431366, tzinfo=tzfile('/usr/share/zoneinfo/Asia/Tokyo'))

ここでtzを指定しないと、naiveなオブジェクトが作られる。

>>> datetime.now()
datetime.datetime(2018, 12, 22, 23, 22, 45, 910050)

余談

naiveなオブジェクトはプログラムを実行する環境に依存するので、awareな方を使った方がいいと思う。

例えば、手元の環境ではdatetime.now()でJSTが返るが、AppEngineではUTCになっている、など。

以上です。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2