🕰️
Python3 で 25:32:1 のような時刻表記を time オブジェクトや datetime オブジェクトに変換する
経緯
最近、入社試験で標題のような処理を実装した。
実務でこういうフォーマットと遭遇するのはごめん被りたいが 再度同じ処理が必要になった際の備忘録としてまとめておきたい。
考察
午前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 time
の time
の方) が適している。
これに変換する方法は以下。
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
Discussion