【Python】datetimeの日時を0埋めせずに文字列整形する

# はじめに
みずほリサーチ＆テクノロジーズの @fujine です。
本記事では、Pythonの[datetime](https://docs.python.org/ja/3/library/datetime.html)ライブラリにおいて、日時データを文字列変換する際に **0埋めしない** 方法を解説いたします。

先に結論を示します。OS毎に書式パラメータが違う理由について、次章以降で解説いたします。

```py
from datetime import datetime

# 2023年8月1日 2時3分4秒のデータを作成
dt = datetime(2023, 8, 1, 2, 3, 4)

# 通常の文字列変換では、月日や時分秒は0埋めされる
dt.strftime('%m月%d日 %H時%M分%S秒')  # '08月01日 02時03分04秒'

# Windowsで0埋めしない方法
dt.strftime('%#m月%#d日 %#H時%#M分%#S秒')  # '8月1日 2時3分4秒'

# Linux/MacOSで0埋めしない方法
dt.strftime('%-m月%-d日 %-H時%-M分%-S秒')  # '8月1日 2時3分4秒'

# OSに依存せず0埋めしない方法
f'{dt.month}月{dt.day}日 {dt.hour}時{dt.minute}分{dt.second}秒'  # '8月1日 2時3分4秒'
```

Pythonのバージョンは3.9、検証したプラットフォームは以下の通りです。
- Windows : Windows 11 21H2
- Linux : Debian GNU/Linux 11
- MacOS: Ventura 13.5

# strftimeメソッドの一部書式はプラットフォームに依存する
datetimeライブラリの[date](https://docs.python.org/ja/3/library/datetime.html#datetime.date.strftime)/[time](https://docs.python.org/ja/3/library/datetime.html#datetime.time.strftime)/[datetime](https://docs.python.org/ja/3/library/datetime.html#datetime.datetime.strftime)クラスでは、日時を文字列に変換するための`strftime`メソッドが提供されています。[書式コード](https://docs.python.org/ja/3/library/datetime.html#strftime-and-strptime-format-codes)を用いることで、年月日や時分秒に加え、曜日やロケールなど様々な情報を出力することが可能です。

ただし、以下公式ドキュメントの通り、**strftimeで使用可能な書式はプラットフォームに依存する**ため、「同じプログラムなのに、LinuxとWindowsで出力結果が異なる！」ということが起こり得ます。前章のコードでOS毎に書式パラメータが違う理由はここにあります。

> Python はプラットフォームの C ライブラリの strftime() 関数を呼び出していて、プラットフォームごとにその実装が異なるのはよくあることなので、サポートされる書式コード全体はプラットフォームごとに様々です。 手元のプラットフォームでサポートされているフォーマット記号全体を見るには、 strftime(3) のドキュメントを参照してください。 サポートされていないフォーマット指定子の扱いもプラットフォーム間で差異があります。

# Windowsで0埋めしない方法
[Windowsのstrftime](https://learn.microsoft.com/ja-jp/cpp/c-runtime-library/reference/strftime-wcsftime-strftime-l-wcsftime-l?view=msvc-170#generic-text-routine-mappings)では、先頭の`0`や空白を削除するために`#`を指定します。

```py
# 通常
dt.strftime('%m月%d日 %H時%M分%S秒')  # '08月01日 02時03分04秒'

# Windowsでは"#"で先頭0を削除
dt.strftime('%#m月%#d日 %#H時%#M分%#S秒')  # '8月1日 2時3分4秒'
```

# Linux/MacOSで0埋めしない方法
[Linuxのstrftime](https://manpages.debian.org/bookworm/manpages-ja-dev/strftime.3.ja.html)(リンクはdebian)では、先頭の`0`や空白を削除するために`-`を指定します。
[MacOSのstrftime](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/strftime.3.html)には同様の説明は無かったものの、実機検証ではLinuxと同じ結果となりました。

```py
# 通常
dt.strftime('%m月%d日 %H時%M分%S秒')  # '08月01日 02時03分04秒'

# Linux/MacOSでは"-"で先頭0を削除
dt.strftime('%-m月%-d日 %-H時%-M分%-S秒')  # '8月1日 2時3分4秒'
```

# OSに依存せず0埋めしない方法
`#`や`-`で0埋めを無効化できることは確認できましたが、実際は「**プラットフォームに依存せず同じ結果を得たい**」というユースケースの方が多いでしょう。

その場合、以下のように **f文字列で整形する** 方法が最もシンプルかつ安全な方法だと私は考えています。コードの文字数は少し増えてしまいますが、`strftime`よりも柔軟な整形が可能です。

```py
f'{dt.month}月{dt.day}日 {dt.hour}時{dt.minute}分{dt.second}秒'  # '8月1日 2時3分4秒'
```

上記以外の方法として
- [platform](https://docs.python.org/ja/3/library/platform.html)ライブラリと`if`文を組み合わせて、プラットフォーム毎に`strftime`の書式を使い分ける
- `dt.strftime('%Y-%m-%d-%H-%M-%S').replace('-0', '-')`のように、replaceメソッドを駆使して先頭の0だけを削除する

等も考えられますが、実装・テストの容易さやコードの読みやすさの観点では、f文字列が一番シンプルかと思われます。

# まとめ
今回は、Pythonのdatetimeライブラリで日時データを0埋めせずに文字列変換する方法をOS毎にご紹介しました。

個人開発であればあまり気にする必要は無いかも知れませんが、複数エンジニアが参画するシステム開発プロジェクトでは開発環境が多様化することも珍しくありません。本記事が、プラットフォーム間の相違の一例としてご参考になれば幸いです。