From 51714a7883c4f66926852074c81703f72ff8b314 Mon Sep 17 00:00:00 2001 From: DXC Date: Wed, 16 Sep 2026 09:08:05 +0800 Subject: [PATCH] =?UTF-8?q?fix:=2082=20=E7=88=AC=E8=99=AB=E4=B8=8A?= =?UTF-8?q?=E6=B8=B8=E6=97=B6=E9=97=B4=E4=B8=BA=20UTC=EF=BC=8C+8=20?= =?UTF-8?q?=E5=B0=8F=E6=97=B6=E8=BD=AC=E5=8C=97=E4=BA=AC=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上游 82 网站返回的 date 数组是 UTC,直接入库会让这批数字命名的设备时间比 实际早 8 小时。 实证(本地库): 这批设备的 check_time 是 2026-02-06 17:11:10(那轮采集完成时刻), 而上游原值落在 09:07:02 ~ 09:10:30,+8h 后正好是 17:07 ~ 17:10 —— 即采集 完成前一分钟。若原值已是北京时间,则意味着这批站点在采集前 8 小时就集体 停止上报、且整齐划一,不合常理。 - 解析后 +timedelta(hours=8)。中国无夏令时,固定偏移与 pytz 转换等价。 - 清洗 T / Z / 毫秒后缀,兼容 ISO 格式。 - 解析失败原样兜底 —— 有值但格式不认识,原样透传给入库层的 staleness_of 再解析,与之前“拿不到时间必须为 None”的约定不冲突。 - 跨日正确:16:00 UTC 顺延至次日 00:00。 注意:本次只改后端源码,需重新打包 exe 才会在服务器生效。 --- 2_1banben/services/crawler_82.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/2_1banben/services/crawler_82.py b/2_1banben/services/crawler_82.py index de4e1ba..35ab87b 100644 --- a/2_1banben/services/crawler_82.py +++ b/2_1banben/services/crawler_82.py @@ -4,7 +4,7 @@ import json import logging from lxml import etree from config import Config -from datetime import datetime +from datetime import datetime, timedelta CONFIG = Config.CRAWLER_CONFIG["82"] @@ -44,9 +44,29 @@ def run_82_logic(): if data: d_list = data.get('date', []) + + # 上游返回的是 UTC,需 +8 小时转北京时间。 + # 实证:库里 check_time 为 2026-02-06 17:11:10(那轮采集完成时刻), + # 而同一批设备的上游原值落在 09:07~09:10,+8h 后正好是 17:07~17:10, + # 即采集完成前一分钟 —— 若原值已是北京时间,则意味着这批站点在采集 + # 前 8 小时就集体停止上报,不合常理。 + # 中国无夏令时,固定 +8h 与 pytz 转换等价。 # 拿不到时间时必须是 None,不能是 "N/A" —— 字符串在入库层是真值, # 会把设备主表已经冻结的有效 latest_time 覆盖掉,令 offset 倒退成"从未同步" - latest = str(d_list[-1]) if d_list else None + latest = None + if d_list: + raw_time_str = str(d_list[-1]) + try: + # 兼容可能的 T 或 Z 等 ISO 格式,先做一下基础清洗 + clean_str = raw_time_str.replace('T', ' ').replace('Z', '').split('.')[0] + dt = datetime.strptime(clean_str, "%Y-%m-%d %H:%M:%S") + # 加上 8 小时转换为北京时间 + dt = dt + timedelta(hours=8) + latest = dt.strftime("%Y-%m-%d %H:%M:%S") + except Exception: + # 如果解析失败,原样返回兜底 + latest = raw_time_str + data_packet['target_time'] = latest data_packet['value'] = f"Data Points: {len(d_list)}" data_packet['raw_json'] = data # 🔥 存完整JSON