KernelRanch
返回文章列表

定时任务遇到夏令时:识别重复与不存在的本地时间

2026-11-13 #python#timezone#scheduling

仓库在纽约安排凌晨执行任务。春季切换时,02:30 可能根本不存在。秋季切换时,01:30 可能出现两次。解析用户输入时先枚举可能的 UTC 时刻,再按产品约定处理零个或两个候选。

1. 用三条输入验证候选数

保存为 dst_lab.py,执行 python dst_lab.py。运行环境需要可用的 IANA 时区数据。缺失时,可以给部署环境添加 tzdata 依赖。

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

def utc_candidates(wall, zone):
    if wall.tzinfo is not None:
        raise ValueError("expected a naive local time")
    found = set()
    for fold in (0, 1):
        aware = wall.replace(tzinfo=zone, fold=fold)
        utc = aware.astimezone(timezone.utc)
        restored = utc.astimezone(zone).replace(tzinfo=None)
        if restored == wall:
            found.add(utc)
    return sorted(found)

ny = ZoneInfo("America/New_York")
examples = [
    ("2024-03-10T02:30", []),
    ("2024-11-03T01:30", ["05:30", "06:30"]),
    ("2024-11-03T03:30", ["08:30"]),
]
for text, expected in examples:
    candidates = utc_candidates(datetime.fromisoformat(text), ny)
    actual = [value.strftime("%H:%M") for value in candidates]
    assert actual == expected
    print(text, "UTC candidates:", actual)

本地实测输出如下。

2024-03-10T02:30 UTC candidates: []
2024-11-03T01:30 UTC candidates: ['05:30', '06:30']
2024-11-03T03:30 UTC candidates: ['08:30']

2. 在创建任务时定义边界行为

候选数含义可以采用的契约
0该本地时刻落在时钟向前跳过的区间请用户改时间,或明确顺延规则
1对应唯一执行时间保存 UTC 时刻
2回拨造成重复由用户选较早或较晚时刻,并显示 UTC 偏移

直接绑定 tzinfo 可以构造带时区对象,但构造成功未验证这个本地时刻真实存在。实验对两个 fold 都做 UTC 往返,剔除回到不同墙上时间的候选,并在 UTC 上去重。

一次预约可以落成 UTC 时刻。对于「每天当地 09:00」,还要持久化当地时区和重复规则,再为每个日期计算执行时间。按上次 UTC 时间加 24 小时,跨夏令时后可能改变当地时刻。

小结

界面接受本地时间时,把时区和重复时刻的选择一并纳入输入。测试至少包含春季缺口、秋季回拨和一个普通时刻。

数据来源与检索时间

检索时间 2026-11-13。

来源URL对应内容
Python zoneinfohttps://docs.python.org/3.11/library/zoneinfo.htmlIANA 数据来源与 fold
PEP 495https://peps.python.org/pep-0495/本地时间歧义及缺失时间

核验说明

  • Python 3.11.9 实测纽约三个历史时刻。业务的顺延和重复触发规则需单独约定。