Python でエポック秒(UNIX 時間)を取得するときの注意点

記事タイトルとURLをコピーする
こんにちは。技術4課の保田(ほだ)です。
初めてブログを書きました。インドの青鬼というとても美味しいビールを段ボール(24缶)で買いました。 GW は快適に過ごせそうです。

要約

Python の datetime 型を文字列に変換する strftime メソッドはプラットフォームによって挙動が異なるのでご注意を。

導入

Python を書いていますと datetime モジュールをよく使いますよね。
Python 初心者の頃はこういうのを見て????となったものです。
from datetime import datetime
一応説明しますと datetime モジュール(ファイル名です)に datetime というクラスが定義されておりまして、その datetime クラスを使いますよ、という意味です。
そんな datetime モジュールですが、文字列と datetime 型の間を行き来することがよくあるかと思います。
そんな中で少々ハマったお話をします。

本題

文字列形式の YYYY-MM-DD を datetime 型に変換したあと、エポック秒に変換します。
 
>>> from datetime import datetime
>>> str_date = '2020-05-01'
>>> dt_date = datetime.strptime(str_date, '%Y-%m-%d')
>>> dt_date
datetime.datetime(2020, 5, 1, 0, 0)
>>> dt_date.strftime('%s')
'1588291200'
 
これは Amazon Linux 2 に Python 3.8.2 を入れて実行しました。
strftime メソッドで datetime 型を文字列に変換していますが、フォーマットとして `%s` を指定することでエポック秒に変換できます。
 
さて、これを Windows でやるとどうなるでしょうか。
 
>>> from datetime import datetime
>>> str_date = '2020-05-01'
>>> dt_date = datetime.strptime(str_date, '%Y-%m-%d')
>>> dt_date
datetime.datetime(2020, 5, 1, 0, 0)
>>> dt_date.strftime('%s')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Invalid format string
  ……。 エラーになりました。Mac では使えます。どうやら UNIX 系でしか使えないみたいです。
曲者なのがドキュメントにも記載がないという点です。
 
Windows だとどうすれば良いでしょうか。
 
>>> dt_date.timestamp()
1588258800.0
このような timestamp メソッドがありますが、戻り値が float 型なので int 型に丸めた上で文字列にしてやる必要があります。 やるとすれば安直ですがこんな感じでしょうか。
>>> str(int(dt_date.timestamp()))
'1588258800'
float 型を int 型に丸める挙動も同じようなので一旦は大丈夫そうですね。
>>> dt_now = datetime(2020, 5, 1, 8, 7, 46, 999999)
>>> dt_now.timestamp()
1588320466.999999
>>> dt_now.strftime('%s')
'1588320466'
>>> str(int(dt_now.timestamp()))
'1588320466'

さいごに

Mac ユーザーが Lambda 用のコードを書いたものを Windows ユーザーがローカルで動作確認するときに遭遇しそう(した)なので、頭の片隅に置いていただけると良いかもしれません。
 

追記 

調べるとちょっと分かったことがあるので続きということで解説させていただきます。

ドキュメントを読み進めると strftime メソッドの振る舞いについてのドキュメントへのリンクがあります。

たしかに %s というものはありません。大文字の %S はありますが、これは秒を表すもので、別物です。

表の下に気になる記述がありますね。

Python はプラットフォームの C ライブラリの strftime() 関数を呼び出していて、プラットフォームごとにその実装が異なるのはよくあることなので、サポートされる書式コード全体はプラットフォームごとに様々です。 手元のプラットフォームでサポートされているフォーマット記号全体を見るには、 strftime(3) のドキュメントを参照してください。

C ライブラリの strftime() 関数を呼び出しているらしいです。
ドキュメントで言われているようにリンクをさらに飛んでみましょう。


%s    紀元 (Epoch; 1970-01-01 00:00:00 +0000 (UTC)) からの秒数。 (TZ)

ありました。

あとはこれの Windows 版を見つけて %s が載っていなければ OK です。
確証はありませんがこれかもしれません。

たしかに %s は載っていませんね。