Python 时间格式化到底怎么选:三种常用写法一次讲清

编程狮(w3cschool.cn) 2026-09-04 11:01:49 浏览数 (32)
反馈

你只要记住一句话就够了:Python 时间格式化优先用 datetime 对象的 strftime 按模板输出,把时间塞进长句就用 f-string,反过来要把字符串还原成对象则用 strptime。这三种写法覆盖了日常九成需求,剩下的差别只是模板符号和异常处理。实际开发里,日志要 2026-09-01 10:00:00 这种可排序的样子,接口文档可能要求 2026/09/01,报表表头又想要中文的年月日,如果每处都手写切片拼接,代码很快就会变成难以维护的字符串泥潭。编程狮的日期时间章节反复提醒过一件事:时间处理最容易翻车的地方不是语法,而是模板写错、时区被忽略、外部输入没有校验。下面这篇笔记会按版本、参数、异常三个维度,把三种写法的边界一次讲清,每段代码都可以直接复制运行。

Python 时间格式化三种写法对比封面

一、为什么要把时间格式化

很多新手会疑惑,数据库里明明已经存好了时间,为什么还要专门做 Python 时间格式化?根本原因是“机器格式”和“人读格式”不是一回事。程序内部通常用时间戳(自 1970-01-01 起的秒数,float 类型)或者 datetime 对象来表达某个时刻,它们方便计算、比较和排序,但人类看不懂 1756698600 这种数字。真正要展示给用户的,必须变成 2026年09月01日 10:30 这类本地化字符串。

第二个容易被忽略的点是可排序性。如果你用 2026/9/1 这种不补零的写法,按字符串排序时 2026/9/10 会排在 2026/9/2 前面,因为字符 1 小于 2;而统一成 %Y-%m-%d(也就是 2026-09-10)之后,字典序和日期序完全一致,日志排查、文件命名、按名称分页都会省心很多。接口对接同理,多数 REST 接口在契约里要求 ISO 8601 格式 2026-09-01T10:30:00,不做格式化根本无法满足。

第三个动机是国际化。不同地区的习惯并不相同:中国常用“年-月-日”,美国常用 MM/DD/YYYY,欧洲不少国家用 DD.MM.YYYY。把格式化逻辑集中收敛到一处,后期切换地区时只改模板字符串,不用去动散落各处的业务代码。

最后还有一层是存储与传输的分离。数据库里建议一律存 UTC 时间或带时区的 timestamp,只在最外层渲染时才转成本地字符串,Python 侧只保留一处渲染入口。这样即使业务扩展到多个时区,历史数据也不需要迁移。把这四层动机理清楚,你就能判断“此刻到底该不该格式化、该用哪种模板”,而不是遇到时间字段就条件反射地拼字符串。

二、用 strftime 按模板输出(最常用)

strftime 是 Python 时间格式化里出场率最高的方法,名字来自 string format time。它在 datetime 和 time 两个模块的对象上都能调用,核心机制是把一组以 % 开头的指令(directive)替换成对应的时间片段。下面是一段可以直接运行的示例:

from datetime import datetime


now = datetime(2026, 9, 1, 10, 30, 0)
print(now.strftime("%Y-%m-%d %H:%M:%S"))
# 输出: 2026-09-01 10:30:00
print(now.strftime("%Y年%m月%d日 %H时%M分"))
# 输出: 2026年09月01日 10时30分

这里的指令含义要记牢:%Y 是四位年份(2026),%m 是两位月份(09),%d 是两位日期(01),%H 是 24 小时制小时(10),%M 是分钟(30),%S 是秒(00)。指令大小写敏感,%m%M 一个是月一个是分,写错不会报错却会输出离谱结果,这也是 Python 项目线上最常见的低级事故之一。想拼中文直接把汉字写在模板里就行,Python 3 的字符串本身就是 Unicode,无需额外编码处理。

关于版本兼容,strftime 在所有 Python 3.x 版本中都稳定存在,行为也几乎没有变化,因此老项目升级时这部分代码通常不用改。若想系统地过一遍模板符号表,建议从Python3 教程的日期时间章节入手,%a(星期缩写)、%b(月份缩写)、%j(一年中的第几天)、%U(周序号)这些冷门指令都列得比较全。实际项目里,日志前缀、导出文件名、报表表头几乎全靠这一个方法,先把它练熟就能覆盖八成场景。

三、用 f-string 直接嵌入(Python 3.6+)

当格式化只是为了把时间塞进一句更长的话里,反复调用 strftime 再做字符串拼接会显得啰嗦。Python 3.6 引入的 f-string 支持在花括号内直接写格式说明符,语法是 {变量:格式},冒号后面的部分和 strftime 的指令完全一致,不需要额外记新规则。示例:

from datetime import datetime


now = datetime(2026, 9, 1, 10, 30, 0)
msg = f"任务开始于 {now:%Y-%m-%d %H:%M:%S},请耐心等待"
print(msg)
# 输出: 任务开始于 2026-09-01 10:30:00,请耐心等待

这段代码的输出和第二节完全相同,但省去了“先生成字符串再拼接”的中间步骤,可读性明显更好。它特别适合写在日志语句、异常提示、通知文案里顺手带上时间。需要注意,这种带格式说明符的写法要求 Python 3.6 及以上版本,停留在 3.5 的老环境会直接抛出语法错误,此时用 str.format 或 strftime 兜底即可,效果等价。

不过 f-string 不适合“同一个时刻要被格式化成多种模板”的场景,那种情况还是先拿到 datetime 对象,再分别调用 strftime 更清晰,也便于把模板抽成常量统一维护。换句话说,Python 时间格式化在简单嵌入时用 f-string 最省事,在复杂编排时 strftime 更可控,两者不是替代关系而是互补关系。写代码时按“是否要嵌进一句长文案”这一条来二选一,基本不会选错。

四、用 datetime 解析字符串

格式化是“对象变字符串”,反过来“字符串变对象”同样常见:用户从表单提交的 2026-09-01 10:30:00、从 CSV 读到的文本列、第三方接口返回的日期字段,都需要还原成 datetime 才能参与计算。这时要用 strptime,它是 strftime 的逆操作,第一个参数是原字符串,第二个参数是与之严格对应的模板:

from datetime import datetime


s = "2026-09-01 10:30:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
print(dt.year, dt.month, dt.day)
# 输出: 2026 9 1
print((dt - datetime(2026, 9, 1)).total_seconds())
# 输出: 37800.0

关键点在于模板必须和字符串“长得一模一样”:字符串里用横杠分隔,模板里就不能写成斜杠;字符串里没有前导零时,用 %m 解析 9 会直接失败。跨平台项目推荐统一保持零填充,因为去零填充的写法在 Windows 和 Linux 上指令并不通用。模板不匹配会抛出 ValueError,所以解析任何外部输入都必须用 try 与 except 包裹,给用户一句友好的提示,而不是让整个请求崩掉。

想动手验证某个字符串能不能被解析,可以打开Python3 在线运行把上面的代码粘进去逐个改着试,不用在本地折腾环境。如果你更习惯边查文档边写,编程狮站内的 python3教程 也可以并排打开对照。记住一条铁律:只要涉及“人手写出来的字符串”,就永远假设它会出错,解析这一步永远要带异常处理,这样整条链路在生产环境才稳得住。

五、三种方式怎么选

把前面三节收敛成一张决策表,你以后不用再纠结。第一种情况,手里已经有 datetime 对象、要生成一个独立的时间串(写日志、拼文件名、填报表单元格),用 strftime,模板自由度最高。第二种情况,要把时间嵌进一段现成文案而且只用一次,用 f-string,代码最短、可读性最好。第三种情况,拿到的是字符串、要转成对象做加减比较,用 strptime,并且一定要处理异常。三者的指令符号完全通用,学会一套 %Y-%m-%d %H:%M:%S 就能通吃。

还有一个组合技巧值得记:入口处先 strptime 解析并校验,中间层一律以 datetime 对象流转和存储,出口处再用 strftime 或 f-string 渲染,这就是“进—存—出”三段式。绝大多数 Python Web 框架的日期字段本质就是这条链路,序列化器负责进出两端,模型层只关心对象。

当你面对一个新需求,先问自己两个问题:现在手上是对象还是字符串?它下一步要去哪里(给人看、给机器算、还是给接口传)?答案自然就浮现了。Python 时间格式化的本质是“对象与字符串之间的双向映射”,难点从来不在语法,而在选对工具和守住边界——把这三个方法各自动手写一遍,下次遇到时间需求你会下意识就选对。

Python 时间格式化三种写法怎么选

总结

Python 时间格式化的本质是“对象与字符串之间的双向映射”:strftime 负责把 datetime 按模板输出成人类可读文本,f-string 在 Python 3.6 及以上版本里把这一步内联进长句,strptime 则把字符串还原成对象以便参与计算。三者共享同一套百分号指令,记忆成本很低,真正需要花心思的是模板一致性、零填充规则和时区处理,这也是 Python 日期模块设计上刻意保持一致的地方。实战中记住九个字——“出用 strftime、嵌用 f-string、进用 strptime”,并给所有外部解析加上异常保护,同时把模板字符串抽成常量集中管理,就能稳稳覆盖绝大多数业务场景,也不会在跨时区扩展时被历史数据反噬。

延伸学习

常见问题

Q:strftime 和 strptime 到底差在哪?

A:结论:一个负责出、一个负责进。
strftime 把 datetime 对象格式化成字符串,strptime 把字符串解析回 datetime 对象。
两者的模板符号完全一致,只是方向相反,记不住时就想“f 是 format 输出、p 是 parse 输入”。

Q:为什么我的 %m 解析 "2026-9-1" 会报 ValueError?

A:结论:模板和字符串必须逐字对应。
%m 要求两位月份(09),而 9 只有一位就会解析失败。
要么把输入补零成 2026-09-01,要么改用不补零的平台专用写法,并注意 Windows 与 Linux 的差异。

Q:Python 2 还能用 f-string 做时间格式化吗?

A:结论:不能,带格式说明符的 f-string 是 Python 3.6 起才有的特性。
Python 2 已经停止维护,新项目应当直接使用 Python 3.8 以上版本。
老环境若暂时无法升级,可用 str.format 或 strftime 代替,输出结果等价。

Q:格式化的时候要不要管时区?

A:结论:只要输出给用户看,就一定要管。
datetime.now() 返回的是不带时区信息的本地 naive 时间,跨时区服务建议改用 datetime.now(timezone.utc)
存储统一用 UTC,渲染时再按目标时区转换,可以避免“时间对了但地区错了”这类难查的坑。

0 人点赞