feat(scheduler): 新增工作日判定工具(法定节假日与调休)

依赖 chinesecalendar(按年收录,1.11.0 覆盖 2004-2026)。口径:非法定节假日、非周末、非调休放假;补班日(调休上班的周六周日)算工作日,纯 weekday 判断做不到。

库缺失或年份未收录(实测 2027 起抛 NotImplementedError)时降级为周一至周五判断并打 [Workday] 警告,宁可偶尔在节假日多发也不让日报停发。库按年发布,次年安排发布后需升级并重建镜像。
This commit is contained in:
yueli
2026-10-03 09:48:38 +08:00
parent 2a841af28f
commit 27ac1e4e82
2 changed files with 69 additions and 1 deletions

View File

@ -0,0 +1,64 @@
"""
工作日判定 —— 供定时任务决定「今天要不要发邮件」。
口径
----
「工作日」= 非法定节假日、非周末、且非法定调休放假的日子;
「补班日」(为凑长假而调休上班的周六/周日)**算工作日**。
★ 这个口径**无法用规则算出来**。中国的放假/调休安排由国务院逐年发布,
纯按 weekday() 判断必然错判:国庆前后的补班周末会被漏发,长假中间的
工作日会被误发 —— 两种都是「该发的不发 / 不该发的发了」的实际故障。
故依赖 chinese-calendar,它内置国务院公布的节假日与调休数据。
★ 但它**按年收录**(1.11.0 覆盖 2004–2026),超出范围会抛
NotImplementedError。因此这里必须兜底:库缺失或该年份尚未收录时,
退化为「周一至周五即工作日」并打警告 ——
宁可偶尔在节假日多发一封,也绝不能让日报因第三方库没更新而**整个停发**:
收不到报表是比多收一封更难排查的静默故障(发件侧一切正常,没人知道
为什么报表没了)。
"""
import logging
from datetime import date, datetime
logger = logging.getLogger(__name__)
try:
from chinese_calendar import is_workday as _cc_is_workday
_CC_AVAILABLE = True
except ImportError: # 依赖未装(例如镜像未随 requirements 重建)
_cc_is_workday = None
_CC_AVAILABLE = False
def is_workday(day=None):
"""
判断某天是否为工作日。
day:date 或 datetime,缺省取今天(**调用方若需北京时间口径,必须自己
传入 `datetime.now(beijing_tz).date()`** —— 本函数不做任何时区换算,
容器时区多为 UTC,直接依赖缺省值会在凌晨前后算错一天)。
"""
if day is None:
day = date.today()
if isinstance(day, datetime):
day = day.date()
if _CC_AVAILABLE:
try:
return bool(_cc_is_workday(day))
except NotImplementedError:
# 该年份尚未被 chinese-calendar 收录(通常是次年安排还没发布)
logger.warning(
"[Workday] chinese-calendar 未收录 %s 的放假安排,"
"本次退化为「仅按周末判断」;请升级 chinesecalendar 包", day
)
except Exception as e: # noqa: BLE001 —— 第三方库任何异常都不该阻断日报
logger.warning(
f"[Workday] chinese-calendar 判定 {day} 出错,退化为周末判断: {e}"
)
else:
logger.warning("[Workday] 未安装 chinese-calendar,退化为「仅按周末判断」")
# 兜底:周一至周五算工作日(无节假日感知,可能误发)
return day.weekday() < 5

View File

@ -35,4 +35,8 @@ tqdm>=4.66.0
# [新增] pgvector 向量数据库支持(以图搜图 / 实时向量提取) # [新增] pgvector 向量数据库支持(以图搜图 / 实时向量提取)
pgvector>=0.2.0 pgvector>=0.2.0
# [新增] HTTP 客户端(Track 系统 Webhook 异步通知) # [新增] HTTP 客户端(Track 系统 Webhook 异步通知)
httpx>=0.24.0 httpx>=0.24.0
# [新增] 中国法定节假日/调休数据(日报仅工作日发送)。
# 按年收录(1.11.0 覆盖 2004–2026),次年数据发布后需 pip install -U chinesecalendar;
# 代码侧已兜底(见 app/utils/workday.py),未升级不会导致日报停发。
chinesecalendar>=1.11.0