HOWTO · Python
在 Python 中将 datetime 转换为带毫秒的字符串
将 Python datetime 转换为正好包含三位毫秒数字的 ISO 风格或自定义字符串。
本页内容
当 ISO 风格结果合适时,使用 value.isoformat(timespec="milliseconds")。当需要自定义布局时,使用带 %f 的 strftime() 并去掉最后三位。两种方法都会把微秒截断为毫秒,而不是四舍五入。
格式化只改变表示形式,不改变 datetime 值本身。示例使用固定输入,因此可以精确验证输出;在选择所需布局后,把这些构造器替换为应用中的值。如果接收系统需要偏移量,请在格式化前让该值带有时区。
使用 isoformat() 获得三位毫秒精度
datetime.isoformat() 是生成 ISO 8601 风格字符串的最清晰选择。timespec="milliseconds" 参数始终输出正好三位秒的小数部分。它可用于 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
六位 microsecond 值 789654 会变成 .789。Python 不会把该值四舍五入为 .790;timespec 控制显示哪些组件,被排除的时间组件会被截断。
当字符串必须跨系统标识一个真实时刻时,请使用带时区的 datetime。naive 值没有 UTC 偏移量,因此它的格式化文本本身无法区分本地时间、UTC 或其他时区。
isoformat() 会保留对象上已有的偏移量;它不会把值转换为 UTC。如果数据契约要求 UTC,请先规范化 datetime。反过来,只有在消费者明确期望本地壁钟时间时,才省略时区转换。
使用 strftime() 创建自定义布局
当需要控制顺序、分隔符或其他字段时,使用 strftime()。%f 指令会生成六位微秒数字。使用 [:-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 总是提供一个零填充的六位字段,即使原始值没有微秒也是如此。在使用 [:-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 为零时省略小数字段,否则输出全部六位微秒数字。因此,str(value) 不保证三位毫秒字段,盲目应用 [:-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
第三行不是有效的毫秒转换:它删除了 :56,因为输入没有小数字段。请优先使用 isoformat(timespec="milliseconds"),或者使用包含 %f 的格式,而不是切片 str() 的可变长度结果。
选择合适的方法
对于机器可读时间戳和标准交换,使用 isoformat(timespec="milliseconds")。它无需手动字符串处理,就能处理零微秒、截断和时区偏移。只有在消费者需要自定义布局时,才使用 strftime() 加 [:-3]。
请根据输出契约而不是方便程度来选择:isoformat() 提供标准化的日期时间形状,strftime() 提供调用方定义的形状,str() 提供适合人类阅读但小数精度可变的默认值。无论哪种情况,都要说明缺少偏移量表示本地时间、约定的 UTC,还是未知时区。
这些方法格式化已有的 datetime;它们不会把它转换为 Unix epoch 以来的毫秒,也不会把字符串解析为 datetime。还要记住,显示的三位数字描述的是毫秒精度,不一定代表时钟或存储源值的准确度。