datetimeの経過時間(日、時、分、秒)計算のための備忘録

# はじめに
深層学習の学習過程の監視として、loguruやloggerなどを使用すると思います。その際、datetime型の日時から経過時間を出力する方法を調べたので、備忘録として残します。

本記事には以下の内容が含まれます。
- datetimeクラス、dateクラスの簡単な使い方
- {datetime、date}クラスと文字列strとの変換のやり方
- datetimeインスタンス同士の減算
- timedeltaから(日、時、分、秒)フォーマットへの変換

## datetimeオブジェクト
- Pythonの標準ライブラリ
- 日時を処理できる
### datetimeのクラス
- datetime.datetime : 日付と時刻
- datetime.date : 日付
- datetime.time : 時刻
- detetime.timedelta : 時間差・経過時間
- detetime.tzinfo : タイムゾーン情報を表すための基底クラス(直接使用はしない)
- datetime.timezone : 標準的なタイムゾーン情報を提供するクラス

# 使い方
## datetime.datetime : 日付と時刻
### datetime.datetime.now()
```python:datetime_test.py
import datetime
dt_now = datetime.datetime.now() # ローカルな日付と時刻を返す
print(type(dt_now), dt_now)
print("Year:", type(dt_now.year), dt_now.year)
print("Month:", type(dt_now.month),dt_now.month)
print("Day:", type(dt_now.day), dt_now.day)
print("Hour:", type(dt_now.hour), dt_now.hour)
print("Minute:", type(dt_now.minute), dt_now.minute)
print("Second:", type(dt_now.second), dt_now.second)
print("Microsecond:", type(dt_now.microsecond), dt_now.microsecond)
```
```console
$ python datetime_test.py
<class 'datetime.datetime'> 2024-11-18 11:48:31.432001
Year: <class 'int'> 2024
Month: <class 'int'> 11
Day: <class 'int'> 18
Hour: <class 'int'> 11
Minute: <class 'int'> 48
Second: <class 'int'> 31
Microsecond: <class 'int'> 432001
```
## datetime.date : 日付
```python:date_test.py
import datetime
dt_now = datetime.date.today() # ローカルな日付のみ
print(type(dt_now), dt_now)
print("Year:", type(dt_now.year), dt_now.year)
print("Month:", type(dt_now.month),dt_now.month)
print("Day:", type(dt_now.day), dt_now.day)
```
```console
$ python date_test.py
<class 'datetime.date'> 2024-11-18
Year: <class 'int'> 2024
Month: <class 'int'> 11
Day: <class 'int'> 18
```
## str、datetime、date型の変換
### date→str
```python:date2str.py
import datetime
date_now = datetime.date.today()
print(type(date_now), date_now)

str_from_date_1 = date_now.strftime('%Y-%m-%d')
print("dateからstr 1", type(str_from_date_1), str_from_date_1)
str_from_date_2 = date_now.strftime('%Y-%m-%d-%H-%M-%S-%f') # date_nowに含まれないものは0
print("dateからstr 2", type(str_from_date_2), str_from_date_2)
```
```console
$ python date2str.py
<class 'datetime.date'> 2024-11-18
dateからstr 1 <class 'str'> 2024-11-18
dateからstr 2 <class 'str'> 2024-11-18-00-00-00-000000
```

### str→{date, datetime}
```python:date2str.py
import datetime
str_1 = "2024-11-18"

# 文字列をdate型、datetime型
date_from_str = datetime.datetime.strptime(str_1, '%Y-%m-%d')
print("strからdate", type(date_from_str.date()), date_from_str.date())
print("strからdatetime", type(date_from_str), date_from_str)
```
```console
$ python:date2str.py
strからdate <class 'datetime.date'> 2024-11-18
strからdatetime <class 'datetime.datetime'> 2024-11-18 00:00:00
```

### datetime→str
```python:datetime2str.py
import datetime
datetime_now = datetime.datetime.now()
print(type(datetime_now), datetime_now)
str_from_datetime_1 = datetime_now.strftime('%Y-%m-%d-%H-%M-%S-%f')
print("datetimeからstr 1",type(str_from_datetime_1), str_from_datetime_1)
str_from_datetime_2 = datetime_now.strftime('%Y-%m-%d')
print("datetimeからstr 2",type(str_from_datetime_2), str_from_datetime_2)
```
```console
$ python datetime2str.py
<class 'datetime.datetime'> 2024-11-18 12:13:37.659586
datetimeからstr 1 <class 'str'> 2024-11-18-12-13-37-659586
datetimeからstr 2 <class 'str'> 2024-11-18
```

### str→(date, datetime)
```python:str2datetime.py
import datetime
str_1 = "2024-11-18-12-13-37-659586"

# 文字列をdate型、datetime型
date_from_str = datetime.datetime.strptime(str_from_datetime_1, '%Y-%m-%d-%H-%M-%S-%f')
print("strからdatetime", type(date_from_str), date_from_str)
print("strからdate", type(date_from_str.date()), date_from_str.date())
```
```console
$ python str2datetime.py
strからdatetime <class 'datetime.datetime'> 2024-11-18 12:13:37.659586
strからdate <class 'datetime.date'> 2024-11-18
```
# 問題
### datetimeインスタンス同士の引き算は可能だが、timedelta型に変化してしまう
- timedelta型の属性
    - .days : 日数
    - .seconds : 日数を除いた秒数
    - .microseconds : 日と秒を除いたマイクロ秒

本来は、以下のフォーマットで出力したいが、時間・分数がtimedeltaに無い
"経過時間 : {days}日-{hours}時-{minutes}分-{seconds}秒"


```python:delta_test.py
start_str = "2024-07-05 15:33:49.845"
finish_str = "2024-07-08 18:53:52.588"
print(type(start_str), start_str)
print(type(finish_str), finish_str)

start_dt = datetime.datetime.strptime(start_str, '%Y-%m-%d %H:%M:%S.%f')
finish_dt = datetime.datetime.strptime(finish_str, '%Y-%m-%d %H:%M:%S.%f')
print(type(start_dt), start_dt)
print(type(finish_dt), finish_dt)

delta_td = finish_dt - start_dt # timedelta型になる
print(type(delta_td), delta_td)
```
```console
$ python delta_test.py
<class 'str'> 2024-07-05 15:33:49.845
<class 'str'> 2024-07-08 18:53:52.588
<class 'datetime.datetime'> 2024-07-05 15:33:49.845000
<class 'datetime.datetime'> 2024-07-08 18:53:52.588000
<class 'datetime.timedelta'> 3 days, 3:20:02.743000
```
# 解決方法
### シンプルに秒数を基に、時間数と分数を計算する
- 調べた限り、直接変換する方法が無いため、関数を作成して解決する
```python:delta_test.py
def delta2str(td):
    days = td.days
    hours, remainder = divmod(td.seconds, 3600)
    minutes, seconds = divmod(remainder, 60)
    return f"{days}日-{hours}時-{minutes}分-{seconds}秒"
    
delta_str = delta2str(delta_td)
print("経過時間：",delta_str)
```
```console
$ python delta_test.py
経過時間： 3日-3時-20分-2秒
```
# おわりに
本記事では、datetimeオブジェクトの簡単な使い方及び、経過時間を計算し、(日、時、分、秒)のフォーマットで出力する方法を記しました。
もし他に良い方法があれば、ご教授いただければ幸いです。
# 参考
公式ドキュメント
https://docs.python.org/ja/3/contents.html