53
34

More than 3 years have passed since last update.

Pythonのtimedeltaで「xx時間」を一発で計算する方法

Posted at

はじめに

ほぼフルリモートでの仕事をするようになり、通勤に時間を費やす必要がなくなりました。その時間を他に使えるのでとても良いのですが、体を動かす機会が減るのと、ポッドキャストを聞く時間が確保できないのが悩みポイントでした。その両方を解決するために毎朝少し離れたスーパー(朝8時開店!)まで歩くのを日課にし始めたのですが、今日聞いていた PythonBytesというポッドキャストで目からウロコなtipsを話していたのでご紹介します。

ポッドキャストで話をしている人たちも「え、そんなことできるの?」「知らなかった」って言ってましたが、 私も聞いていて驚きました。直接聞いてみたい方はEpisode #190の27分ころです。

timedeltaとは

timedeltaはpythonの標準ライブラリに含まれる機能で datetimeモジュールに含まれています。datetime同士を引き算した時に timedelta型のデータが返ってきます。

現在時刻を取ってくるdatetime.now() を二回呼んで、その差をとってみます。

>>> from datetime import datetime, timedelta
>>> d0 = datetime.now()
>>> d1 = datetime.now()
>>> td = d1 - d0
>>> td
datetime.timedelta(seconds=1, microseconds=508102)

差の結果はtimedelta型のデータで、この場合2つの時刻の差分は 1秒 + 508102マイクロ秒 = 1.508102秒 ということになります。それぞれの値は属性値として取得できます。

>>> td.days
0
>>> td.seconds
1
>>> td.microseconds
508102

ここで、もう少し大きな差分を考えてみましょう。

>>> d0 = datetime(2020,7,31,22,5,0, 113459)
>>> d1 = datetime(2020,8,3,5,55,26, 93450)
>>> d1 - d0
datetime.timedelta(days=2, seconds=28225, microseconds=979991)

7月31日の22時5分0.113459秒から8月3日の5時55分26.093450秒まで。2つのdatetimeを引くだけでその差は2日と28225.979991秒ということがわかります。この例では月をまたいだ日付の差分をとっていて、手でやると面倒で間違いやすそうな計算ですが、datetimeがよろしくやってくれてるのはとても助かります。

timedeltaを時間換算する

このように簡単に計算できるものの、「2日と28225.979991秒」って微妙にわかりにくいですよね。これって何時間なのかな?と思った時にとたんにハードルが上がります。パッと思いつくのは属性値を取り出して計算してみること。

>>> td.days * 24 + (td.seconds + td.microseconds / 1000000 ) / 60 / 60
55.8405499975

あるいは total_seconds()メソッドを使えばもう少し簡単になります。

>>> td.total_seconds() / 60 / 60
55.840549997500005

こちらは少し誤差がでますね。

いずれにしても、それほど難しい計算ではないけど、せっかく timedeltaという専用の型があるのにそれを使ってできないというのが悔しい。

でも実はできるんです。それが今日の本題ですが、解はとても単純で「計算したい単位のtimedeltaで割り算する」です。

例えば上の場合だと

>>> td / timedelta (hours=1)
55.8405499975

おおー、凄くないですか?なぜこうなるのかを少しだけ書いておきます。

timedeltaは属性値としては days, seconds, microseconds の3つですが、コンストラクターはそれ以外の時間単位もキーワード引数でサポートしています。

>>> timedelta(minutes=1)
datetime.timedelta(seconds=60)
>>> timedelta(hours=1)
datetime.timedelta(seconds=3600)
>>> timedelta(weeks=1)
datetime.timedelta(days=7)

見ておわかりのように、別の単位で指定された場合は days, seconds, microsecondsに正規化されてtimedeltaの属性として保存されます。

そして、timedelta同士の割り算は2つの時間間隔の比を計算することになり、結果はfloat (浮動小数点型)になります。したがって、「時間」単位であれば timedelta(hours=1)で割ることで目的の値を得られます。

これの応用で、例えば、「5/6から8/19は何週間かな?」と思った時には

>>> (datetime (2020, 8,19) - datetime (2020, 5, 6)) / timedelta(weeks=1)
15.0

と一発で計算できます。

まとめ

datetimeがPythonに導入されてからだいぶ経ちますが、今までこういうtimedeltaの使い方をしたことがありませんでした。Podcastによると、これは別に裏ワザということでもなくtimedeltaの作者自身が意図した使い方らしいのですが、それなのであればドキュメントに例示しておくとかもう少し広める努力をして欲しかったなと思います(笑)

53
34
1

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
53
34