🕰️

Python3 で 25:32:1 のような時刻表記を time オブジェクトや datetime オブジェクトに変換する

2023/10/31に公開

経緯

最近、入社試験で標題のような処理を実装した。
実務でこういうフォーマットと遭遇するのはごめん被りたいが 再度同じ処理が必要になった際の備忘録としてまとめておきたい。

考察

午前1時(AM 1:00)を便宜上、25時と言ったりすることがある。
このメンタルモデルをシステムに採用する時刻表現にそのまま導入してしまうと日付の変換が面倒なことになる。

"2023-10-30 12:27:05" や "2023-10-31 01:32:01" と言った文字列なら何の問題もない。
例えば、こう言った文字列から datetime オブジェクトを作成するのは容易。

datetime.strptime("2023-10-30 12:27:05", '%Y-%m-%d %H:%M:%S')
datetime.strptime("2023-10-31 01:32:01", '%Y-%m-%d %H:%M:%S')

ただ、冒頭で触れたような書式の文字列として "25:32:1" といった類のものが来たら処理に一工夫必要。

time オブジェクトへの変換

日付という情報を持たなくていいなら1日の中の時刻を表現する time オブジェクト (time モジュールではなくて from datetime import timetime の方) が適している。
これに変換する方法は以下。

from datetime import time
time_str = "25:32:1"
hour, minute, second = map(int, time_str.split(":"))
hour %= 24
time(hour, minute, second)  # datetime.time(1, 32, 1)

datetime オブジェクトへの変換

日付の情報が欠損しているので実装者側で補う必要はある。
ただ、短絡的に日付を補完して datetime.strptime("2023-10-30 25:32:01", '%Y-%m-%d %H:%M:%S') としても当然 ValueError となるのでこの辺の留意も必要。

また、42時などを認めると処理が煩雑になるし人間が理解しやすくなる実益もないと思うので上限も設定することにした。

ここでは以下のような関数を実装して datetime オブジェクトに変換を行うようにした。

from datetime import datetime, timedelta, time

def convert_time_str_to_datetime(time_str: str, base_date: datetime = None, hour_limit: int = 30) -> datetime:
    if base_date is None:
        base_date = datetime.today().date()
    else:
        base_date = base_date.date()

    input_hour, input_minute, input_second = map(int, time_str.split(":"))

    if input_hour >= hour_limit:
        raise ValueError(f"Hour value is out of limit. Should be less than {hour_limit}.")

    if input_hour >= 24:
        base_date += timedelta(days=1)
        input_hour %= 24

    return datetime.combine(base_date, time(input_hour, input_minute, input_second))

print(convert_time_str_to_datetime("15:30:20"))  # 今日の15:30:20
print(convert_time_str_to_datetime("25:32:1"))   # 翌日の1:32:01
print(convert_time_str_to_datetime("30:05:01"))  # ValueError
print(convert_time_str_to_datetime("15:30:20", datetime(2023, 10, 30)))  # 2023-10-30の15:30:20

おまけ

Pythonで、2つの時刻の間でn分単位で何回区切れるかを算出する。例えば30分毎に課金するロジックなどで使用

Discussion