多栈应用夏令时时间问题处理及已存储历史时间数据修复咨询
后续夏令时问题规避方案
- 全链路统一使用UTC时间存储
- Python采集端替换时间生成逻辑:不要使用
datetime.now()(该方法返回设备本地时区时间,存在夏令时偏移),改为返回UTC时间,代码修改为:
from datetime import datetime, timezone def writeData(data): data['acktime'] = datetime.now(timezone.utc) # 后续POST逻辑不变
- 调整MySQL时区配置:将全局时区设置为UTC,避免数据库自动转换时间产生歧义,执行SQL:
SET GLOBAL time_zone = '+00:00'; SET SESSION time_zone = '+00:00';
同时确认Laravel数据库连接配置中没有额外设置时区,保证读写时间都是UTC格式。
- Laravel配置保持
app.php中的timezone为Europe/London即可,该配置仅用于前端展示、报告生成时转换为当地时间,不影响存储逻辑。
- 调整分组统计逻辑
如果需要按伦敦当地时间做天/小时分组,不要直接使用format('Y-m-d')或format('Y-m-d H')作为分组key,夏令时切换时会出现重复的时间字符串导致分组错误,改为携带时区偏移生成key:
$weatherdata = rawData::all() ->groupBy(function (RawData $item) { // 按天分组用该格式 return $item->acktime->timezone('Europe/London')->format('Y-m-d P'); // 按小时分组用该格式 // return $item->acktime->timezone('Europe/London')->format('Y-m-d H P'); }) ->each(function (Collection $day) { foreach ($day as $value){ Log::info($value); } Log::info('NEXT DAY'); });
夏令时切换时重复的2点时段,会因为偏移量分别为+01:00和+00:00生成不同的key,不会被分到同一组。
存量数据修复方案
- 时间校准
你之前未将acktime加入$dates属性时,Laravel未做时区转换,存储的是Python上传的伦敦本地时间,需要批量将存量数据转换为UTC时间:
对每条记录,根据acktime的字面时间和synctime的入库时间,判断当时所处的夏令时状态,将伦敦本地时间转换为对应的UTC时间回写。比如2021年10月31日伦敦时间02:00出现两次,第一次对应UTC 01:00,第二次对应UTC 02:00,可通过synctime的先后顺序区分两次记录。 - 历史报告重算
所有存量时间校准完成后,重新执行历史时段的统计定时任务,替换之前错误的统计结果即可。
内容的提问来源于stack exchange,提问作者Stefano Martini
相关产品推荐
相关产品推荐

