Python zoneinfo 与 fold 结合时如何格式化重复时间
夏令时回拨或其他时区偏移回退时,同一个本地钟面时间可能出现两次。Python 的 zoneinfo 会用 fold=0 表示较早的那次,用 fold=1 表示较晚的那次;但 strftime() 默认不会把 fold 单独打印出来。实际格式化时,应至少同时输出本地时间、%Z、%z 和 fold,必要时再附上 UTC 值。
fold=0和fold=1不是两个时区,而是同一重复钟面时间的两个时刻选择。%Z给出时区名,%z给出 UTC 偏移;它们与显式fold组合后才适合排查日志。- 业务存储优先保留 aware datetime 或 UTC,展示层再把重复时间的选择写清楚。
先用 ZoneInfo 选出重复时间的两个时刻
ZoneInfo 代表 IANA 时区规则。以美国洛杉矶 2020 年回拨为例,2020-11-01 01:30 出现两次:第一次仍是 PDT,偏移为 -07:00;第二次已经是 PST,偏移为 -08:00。构造本地时间后,用 replace(fold=1) 选中第二次出现的钟面时间。

from datetime import datetime, timezone
from zoneinfo import ZoneInfo
la = ZoneInfo("America/Los_Angeles")
# fold=0 表示回拨前的第一次 01:30。
first = datetime(2020, 11, 1, 1, 30, tzinfo=la, fold=0)
# 只改变重复时间的选择,不改变日期、时分或时区规则。
second = first.replace(fold=1)
for label, value in (("first", first), ("second", second)):
print(
label,
value.isoformat(),
"fold=", value.fold,
"utc=", value.astimezone(timezone.utc).isoformat(),
)
first 2020-11-01T01:30:00-07:00 fold= 0 utc= 2020-11-01T08:30:00+00:00
second 2020-11-01T01:30:00-08:00 fold= 1 utc= 2020-11-01T09:30:00+00:00
这里的关键不是把字符串改成“第一次”或“第二次”,而是让对象携带有效的时区规则和 fold。如果时间来自 UTC 再调用 astimezone(la),Python 会根据转换结果设置正确的 fold;如果是用户手工输入本地钟面时间,则必须由业务规则、选择框或其他上下文决定取哪一次。
把 offset、时区名和 fold 一起格式化
strftime 可以输出时区名和偏移:%Z 是时区名称,%z 是类似 -0700 的 UTC 偏移。由于格式化指令没有一个通用的 %fold,应在格式字符串外显式拼接 value.fold。

def format_ambiguous_time(value: datetime) -> str:
# %Z 说明时区名,%z 说明偏移,fold 说明重复时间的选择。
local_part = value.strftime("%Y-%m-%d %H:%M:%S %Z %z")
# UTC 便于跨服务排序和排查,保留 +00:00 这样的明确偏移。
utc_part = value.astimezone(timezone.utc).isoformat()
return f"{local_part} [fold={value.fold}] [utc={utc_part}]"
print(format_ambiguous_time(first))
print(format_ambiguous_time(second))
输出会类似 2020-11-01 01:30:00 PDT -0700 [fold=0] 和 2020-11-01 01:30:00 PST -0800 [fold=1]。对用户界面,可把 fold=0 显示为“回拨前”,把 fold=1 显示为“回拨后”;对日志则建议同时记录 ISO 8601 值和 UTC 值,避免下游只读取前面的钟面时间。
存储与测试要分清展示格式和时间身份
重复时间最容易在序列化和排序时丢失信息。仅保存 2020-11-01 01:30:00 会丢掉时区与偏移;只保存带偏移字符串虽然能区分这两个例子,但跨服务比较时仍应统一解析为 aware datetime 或 UTC。展示格式可以面向人,存储格式则要保留能定位具体时刻的字段。
| 场景 | 建议保留 | 不要只依赖 |
|---|---|---|
| 日志排查 | 本地时间、%Z、%z、fold、UTC | 没有偏移的 HH:MM |
| 接口传输 | 带偏移的 ISO 8601 或 UTC | naive datetime |
| 人工录入 | 时区、重复时间选项、fold | 默认猜测第一次或第二次 |
回归测试至少断言三件事:两个对象的 fold 不同;utcoffset() 不同;转换到 UTC 后的结果不同。不要只比较 strftime("%H:%M"),因为那恰好会把两个事件格式化成同一个钟面字符串。
相关问题
fold=1 在所有时间里都代表夏令时结束吗?
不是。它表示重复区间中的较晚一次,具体偏移由对应 tzinfo 的时区规则决定,不能把它硬编码成“标准时间”。
为什么只调用 strftime 看不出 fold?
strftime 有时区名和偏移指令,但没有通用的 fold 指令。需要在格式化结果后显式拼接 value.fold。
从 UTC 转成本地时间还需要手动设置 fold 吗?
通常不需要。对带时区的 UTC 时间调用 astimezone() 时,zoneinfo 会根据目标时区规则设置正确的 fold;手工创建本地钟面时间时才需要明确选择。
Python TypeIs 为什么比 TypeGuard 更适合否定分支
- 上一篇
- Python TypeIs 为什么比 TypeGuard 更适合否定分支
- 下一篇
- Python logging.Filter 返回 False 时怎样阻止单条记录
-
- 文章 · python教程 | 11分钟前 | Python教程 · 进程管理 · Python subprocess.Popen TimeoutExpired 进程组 start_new_session killpg
- Python subprocess.Popen start_new_session 怎样清理进程组
- 340浏览 收藏
-
- 文章 · python教程 | 13分钟前 |
- Python contextlib.chdir 为什么不适合并发任务共享
- 241浏览 收藏
-
- 文章 · python教程 | 13分钟前 | Python handler 日志过滤 logging.Filter
- Python logging.Filter 返回 False 时怎样阻止单条记录
- 447浏览 收藏
-
- 文章 · python教程 | 18分钟前 |
- Python zipfile.Path 怎样读取压缩包内的嵌套资源
- 157浏览 收藏
-
- 文章 · python教程 | 23分钟前 | 协程 · 任务调度 · Python教程 · asyncio · 兼容性 · Python asyncio 异步调度 create_task eager_start
- Python asyncio.create_task eager_start 如何影响调度
- 155浏览 收藏
-
- 文章 · python教程 | 29分钟前 | Python CancelledError TaskGroup asyncio.timeout 嵌套超时
- Python asyncio.timeout 怎样把嵌套任务限制在总时限内
- 215浏览 收藏
-
- 文章 · python教程 | 11小时前 | 并发编程 · Python教程 · Python multiprocessing Pool initializer spawn initargs 多进程配置
- Python multiprocessing spawn 传递初始化配置的方案
- 295浏览 收藏
-
- 文章 · python教程 | 11小时前 | 文件处理 · 标准库 · csv · python · 数据导入 · Python csv DictReader DictWriter 空行 newline lineterminator
- Python csv newline 参数避免空行的文件处理
- 365浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 1019次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 1021次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1155次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1122次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 963次使用
-
- Go语言中DateTime的用法介绍
- 2022-12-28 431浏览
-
- go格式“占位符”输入输出 类似python的input
- 2023-01-19 346浏览
-
- Golang如何调用Python代码详解
- 2023-01-07 235浏览
-
- HTTP 的 response 中的响应体和头部是分开发送的吗?
- 2023-01-28 387浏览
-
- B站等视频网站的弹幕用的是 websocket 还是轮询?
- 2023-02-16 447浏览

