【Python】時刻差分の計算

PythonのTopに戻る


 

 一般的な時刻の計算

datetimeライブラリからdatetimeモジュールのtimedeltaクラスをインポートすれば計算できる。

from datetime import datetime, timedelta

# 始点と終点の時刻を定義
start_time = datetime.strptime("Dec 2 04:35", "%b %d %H:%M")
end_time = datetime.strptime("Dec 4 07:39", "%b %d %H:%M")

# 期間(時刻差分)の計算
duration = end_time - start_time

# 時間と分への変換
duration_hours = duration.total_seconds() // 3600
duration_minutes = (duration.total_seconds() % 3600) // 60

print(duration_hours, duration_minutes)

これは 12/2 04:35 から 12/4 07:39 までに経過した時間を計算するスクリプトである。なお、月がDecなどの文字列の場合、時刻のフォーマットは %b であることに注意。12のように整数値であれば小文字の %m とする。大文字の %M は「分」なので間違えないように。

☑POINT

datetimeモジュールはグレゴリオ暦に基づいており、timedeltaクラスでは閏年の日付も考慮されている。このため、例えば2月29日のような閏年の日付を処理することも可能である。

秒数を「日:時間:分:秒」の形式に変換する関数は以下のようになる。剰余をうまく使うのが良いだろう。

def convert_seconds_to_dhms(seconds):
    days = seconds // (3600 * 24)
    hours = (seconds % (3600 * 24)) // 3600
    minutes = (seconds % 3600) // 60
    remaining_seconds = seconds % 60
    return days, hours, minutes, remaining_seconds

# 例:350624秒を日、時、分、秒に変換する
example_seconds = 350624
converted_time = convert_seconds_to_dhms(example_seconds)
converted_time

これを実行すると (4, 1, 23, 44) と返されるので、「350624秒」は「4日1時間23分44秒」であることが分かる。

四則演算の例も見てみよう。例えば、平均して17分かかる計算処理を128回行う必要があるとする。この作業を2023年12月1日20時30分から開始した場合、いつ終了するか、という計算を行うことができる。

from datetime import datetime, timedelta

# 開始日時
start_time = datetime(2023, 12, 1, 20, 30, 0)

# バッチ処理1回あたりの平均実行時間(例:15分)
batch_duration = 17 * 60 # 15分を秒に変換

# 処理回数
batch_count = 128

# 全体の処理時間の見積もり
total_duration = batch_duration * batch_count

# 終了時刻の計算
end_time = start_time + timedelta(seconds=total_duration)

# 終了時刻の表示
print(end_time)

これを実行すると「2023-12-03 08:46:00」となるので、翌日の朝8時46分ごろに終了すると見積もられる。

 タイムゾーンを跨ぐ時刻の計算

タイムゾーンを跨ぐ時刻の計算にはdatetimeモジュールのtimedeltaクラスおよびtimezoneクラスを利用する。

from datetime import datetime, timedelta, timezone

# タイムゾーンの定義 (UTCオフセットで)
tz_ny = timezone(timedelta(hours=-5)) # ニューヨークはUTC-5時間
tz_tokyo = timezone(timedelta(hours=9)) # 東京はUTC+9時間

# New Yorkの時刻を定義
ny_time = datetime(2023, 1, 1, 12, 0, 0, tzinfo=tz_ny)

# Tokyoの時刻に変換
tokyo_time = ny_time.astimezone(tz_tokyo)

# Tokyoの時刻を出力
print("New York time:", ny_time.strftime('%Y-%m-%d %H:%M:%S %Z%z'))
print("Tokyo time:", tokyo_time.strftime('%Y-%m-%d %H:%M:%S %Z%z'))

# Tokyoの時刻に3時間加算
tokyo_time_later = tokyo_time + timedelta(hours=3)

# 加算後の時刻を出力
print("Tokyo time + 3 hours:", tokyo_time_later.strftime('%Y-%m-%d %H:%M:%S %Z%z'))

これはNY時間の2023年元日の正午を日本時間(東京時間)に変換するものである。結果は変換後が「2023-01-02 02:00:00 UTC+09:00+0900」、3時間の加算後が「2023-01-02 05:00:00 UTC+09:00+0900」となる。

または、以下のようにpytzライブラリを使うこともできる。

from datetime import datetime, timedelta
import pytz

# タイムゾーンの定義
tz_ny = pytz.timezone('America/New_York')
tz_tokyo = pytz.timezone('Asia/Tokyo')

# New Yorkの時刻を定義
ny_time = tz_ny.localize(datetime(2023, 1, 1, 12, 0, 0))

# Tokyoの時刻に変換
tokyo_time = ny_time.astimezone(tz_tokyo)

# Tokyoの時刻を出力
print("New York time:", ny_time.strftime('%Y-%m-%d %H:%M:%S %Z%z'))
print("Tokyo time:", tokyo_time.strftime('%Y-%m-%d %H:%M:%S %Z%z'))

# Tokyoの時刻に3時間加算
tokyo_time_later = tokyo_time + timedelta(hours=3)

# 加算後の時刻を出力
print("Tokyo time + 3 hours:", tokyo_time_later.strftime('%Y-%m-%d %H:%M:%S %Z%z'))

結果は変換後が「2023-01-02 02:00:00 JST+0900」、3時間の加算後が「2023-01-02 05:00:00 UTC+09:00+0900」となり、正しく求められている。

⚠️pytzを利用する際の注意

UTCオフセットを除き、datetimeのコンストラクタにpytz由来のtimezone(tzinfo)を渡すと誤った時刻が得られてしまうことがある。以下に例を示す。

from datetime import datetime, timedelta
import pytz

# タイムゾーンの定義
tz_ny = pytz.timezone('America/New_York')
tz_tokyo = pytz.timezone('Asia/Tokyo')

# New Yorkの時刻を定義【この部分がNG!】
ny_time = datetime(2023, 1, 1, 12, 0, 0, tzinfo=tz_ny)

# Tokyoの時刻に変換
tokyo_time = ny_time.astimezone(tz_tokyo)

# Tokyoの時刻を出力
print("New York time:", ny_time.strftime('%Y-%m-%d %H:%M:%S %Z%z'))
print("Tokyo time:", tokyo_time.strftime('%Y-%m-%d %H:%M:%S %Z%z'))

# Tokyoの時刻に3時間加算
tokyo_time_later = tokyo_time + timedelta(hours=3)

# 加算後の時刻を出力
print("Tokyo time + 3 hours:", tokyo_time_later.strftime('%Y-%m-%d %H:%M:%S %Z%z'))

2023-01-02 01:56:00 JST+0900となり、4分のズレが生じてしまっている。これは、pytzライブラリがタイムゾーンの歴史的な変更や夏時間を正確に扱うために内部で行っている計算の結果を datetime.timezone で正しく反映できないことによると考えられる。

このようにdatetimeのコンストラクタにtzinfoを直接渡すのではなく、localize()メソッドを使用することが重要である。

 UNIX時間の計算

UNIX時間(またはエポック時間)による時刻差分の計算は、日時をUNIX時間(1970年1月1日0時0分0秒UTCからの経過秒数)に変換してから行われる。UNIX時間の演算はdatetimeモジュールとtimeライブラリで実行できる。

☑POINT

UNIX時間は date +%s コマンドで取得可能。

UNIX時刻を日本標準時(JST)に変換するには、まずUNIX時刻をUTCのdatetimeオブジェクトに変換し、その後に日本標準時(UTC+9)に変換すればよい。

from datetime import datetime, timedelta

# UNIX時刻の例(2021年11月30日0時0分0秒UTCの例)
unix_timestamp = 1638230400

# UNIX時刻をUTCのdatetimeオブジェクトに変換
utc_datetime = datetime.utcfromtimestamp(unix_timestamp)

# UTCからJST(UTC+9)に変換
jst_datetime = utc_datetime + timedelta(hours=9)

# 結果の表示
print(jst_datetime)

結果は「2021-11-30 09:00:00」となり、UTC+9の時刻が正しく算出されている。

当然ながら、UNIX時刻の差分も計算できる。

from datetime import datetime
import time

# 2つの日時を定義
datetime1 = datetime(2023, 1, 1, 12, 0, 0)
datetime2 = datetime(2023, 1, 2, 12, 0, 0)

# UNIX時間に変換
unix_time1 = time.mktime(datetime1.timetuple())
unix_time2 = time.mktime(datetime2.timetuple())

# 時刻差分を計算
time_difference = unix_time2 - unix_time1

# 結果を表示
print(time_difference)

ただし、この計算はUNIX時間に変換する必要性が無い。以下のようなUNIX時間における経過時間の計算では時刻関連のモジュールすら必要ない。

# UNIX時刻の定義
unix_timestamp_start = 1638230400 # 開始時刻
unix_timestamp_end = 1701760000 # 終了時刻

# 経過時間の計算(秒単位)
elapsed_time_seconds = unix_timestamp_end - unix_timestamp_start

# 秒を日時分秒に変換する関数
def seconds_to_dhms(seconds):
    days = seconds // (3600 * 24)
    hours = (seconds % (3600 * 24)) // 3600
    minutes = (seconds % 3600) // 60
    remaining_seconds = seconds % 60
    return days, hours, minutes, remaining_seconds

# 経過時間を日時分秒に変換
elapsed_time_dhms = seconds_to_dhms(elapsed_time_seconds)
print(elapsed_time_dhms)

結果は(735, 7, 6, 40)となり、735日7時間6分40秒が経過したと分かる。


PythonのTopに戻る