HOWTO · Python
Python の `datetime` をミリ秒付き文字列に変換する
Python の datetime を、ちょうど 3 桁のミリ秒を含む ISO 風またはカスタム文字列に変換します。
このページの内容
value.isoformat(timespec="milliseconds") は ISO 風の結果でよい場合に使います。独自の並びが必要な場合は、strftime() で %f を使い、末尾 3 桁を取り除きます。どちらの方法も、マイクロ秒を丸めるのではなくミリ秒へ切り捨てます。
書式化は表現を変えるだけで、datetime 値そのものは変えません。例では出力を正確に確認できるよう固定入力を使います。必要なレイアウトを選んだ後で、これらのコンストラクタをアプリケーションの値に置き換えてください。受け取り側がオフセットを期待する場合は、書式化の前に値をタイムゾーン対応にします。
isoformat() で 3 桁のミリ秒精度を使う
datetime.isoformat() は、ISO 8601 風の文字列にする最も明確な選択です。timespec="milliseconds" 引数は、秒の小数部を常にちょうど 3 桁で出力します。Python 3.6 以降で利用できます。
小文字の複数形文字列 "milliseconds" を正確に渡します。ほかの対応済み timespec 値は別の精度を選び、未知の値は ValueError を送出します。下流のスキーマが一定のフィールド幅を要求する場合、既定の "auto" に頼るより、この明示的な引数の方が適切です。
次の決定的な例ではタイムゾーン対応の datetime を使うため、isoformat() が UTC オフセットを保持することも確認できます。
"""Show the recommended ISO-style millisecond formatting behavior."""
from datetime import datetime, timezone
value = datetime(2026, 9, 16, 12, 34, 56, 789654, tzinfo=timezone.utc)
print(value.isoformat(timespec="milliseconds"))
出力:
2026-09-16T12:34:56.789+00:00
6 桁の microsecond 値 789654 は .789 になります。Python は値を .790 に丸めません。timespec は表示する構成要素を制御し、除外された時刻要素は切り捨てられます。
文字列がシステム間で実際の瞬間を識別する必要がある場合は、タイムゾーン対応の datetime を使います。naive な値には UTC オフセットがないため、その書式化済みテキストだけではローカル時刻、UTC、または別のゾーンを区別できません。
isoformat() はオブジェクトに既に付いているオフセットを保持します。値を UTC に変換するわけではありません。データ契約が UTC を要求する場合は、先に datetime を正規化してください。逆に、利用側がローカルの壁時計時刻を意図している場合だけ、タイムゾーン変換を省きます。
strftime() でカスタムレイアウトを使う
順序、区切り文字、その他のフィールドを制御する必要がある場合は strftime() を使います。%f ディレクティブは 6 桁のマイクロ秒を生成します。[:-3] によるスライスは末尾 3 桁を意図的に削除し、ミリ秒精度を残します。
"""Show millisecond precision in a custom datetime string format."""
from datetime import datetime
value = datetime(2026, 9, 16, 12, 34, 56, 789654)
print(value.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3])
出力:
2026-09-16 12:34:56.789
このスライスは安全です。%f は元の値にマイクロ秒がなくても、ゼロ埋めされた 6 桁のフィールドを常に供給するためです。[:-3] を使う前に、フォーマットの末尾を .%f にしておいてください。そうしないと、別のフィールドから文字を削ってしまう可能性があります。
この操作は丸めではなく切り捨てです。たとえば 789999 マイクロ秒も 789 ミリ秒になります。仕様が丸めを要求する場合は、書式化前に datetime を丸め、次の秒への繰り上がりを処理してください。単に %f をスライスしてもその規則は実装できません。
インポート形式によってクラスの呼び出し方が決まります。from datetime import datetime の場合は datetime.now() を呼びます。代わりに import datetime と書いた場合は datetime.datetime.now() を呼びます。
str() とスライス境界を理解する
単純な str(value) は value.isoformat(" ") と同等です。既定の timespec="auto" は、microsecond がゼロなら小数部を省略し、それ以外なら 6 桁すべてのマイクロ秒を出力します。そのため str(value) は 3 桁のミリ秒フィールドを保証せず、無条件に [:-3] を適用するのは危険です。
この可変幅の動作は簡易表示には便利ですが、固定幅フィールドには不向きです。スライス前に小数点を確認すれば秒を壊すことは避けられますが、isoformat(timespec="milliseconds") が既に処理しているロジックを重複させ、タイムゾーンサフィックスにも追加の注意が必要になります。
この境界例は、999999 マイクロ秒でもミリ秒出力が切り捨てられること、そして単数形の値 "millisecond" が無効であることも示します。
"""Expose truncation, zero-microsecond slicing, and invalid-timespec boundaries."""
from datetime import datetime
almost_next_second = datetime(2026, 9, 16, 12, 34, 56, 999999)
without_fraction = datetime(2026, 9, 16, 12, 34, 56)
print(almost_next_second.isoformat(timespec="milliseconds"))
print(str(without_fraction))
print(str(without_fraction)[:-3])
try:
without_fraction.isoformat(timespec="millisecond")
except ValueError as error:
print(f"{type(error).__name__}: {error}")
出力:
2026-09-16T12:34:56.999
2026-09-16 12:34:56
2026-09-16 12:34
ValueError: Unknown timespec value
3 行目は有効なミリ秒変換ではありません。入力に小数部がないため :56 を削除しています。可変長の str() の結果をスライスするのではなく、isoformat(timespec="milliseconds") を優先するか、%f を含むフォーマットを使ってください。
適切な方法を選ぶ
機械可読なタイムスタンプや標準的な交換には isoformat(timespec="milliseconds") を使います。ゼロのマイクロ秒、切り捨て、タイムゾーンオフセットを手作業の文字列操作なしで扱えます。利用側がカスタムレイアウトを要求する場合は、strftime() と [:-3] を使います。
便利さではなく出力契約で選びます。isoformat() は標準化された日時の形を提供し、strftime() は呼び出し側が定義する形を提供し、str() は小数精度が可変の人間向け既定値を提供します。どの場合も、オフセットがないことがローカル時刻、慣例上の UTC、または不明なタイムゾーンのどれを意味するのかを文書化してください。
これらの方法は既存の datetime を書式化します。Unix エポックからのミリ秒へ変換したり、文字列を datetime に解析したりするものではありません。また、表示される 3 桁はミリ秒精度を表すだけで、時計や保存元の値の正確さを必ずしも示さないことも覚えておいてください。