修改Round to nearest interval函数以支持1小时以上时间间隔
时间向下取整函数对长间隔(1小时以上)的修复方案
现有一个用于将时间戳向下取整到最近时间间隔的函数:
function roundToNearest(value, interval) { return Math.floor(value/interval) * interval; }
当前测试时间:Date.now() 对应的本地时间为 Thu Sep 01 2022 05:38:11 GMT+0300 (Eastern European Summer Time)
测试不同时间间隔的结果:
- 5分钟:
new Date(roundToNearest(Date.now(), 1000*60*5))→ Thu Sep 01 2022 05:35:00 GMT+0300(符合预期) - 15分钟:
new Date(roundToNearest(Date.now(), 1000*60*15))→ Thu Sep 01 2022 05:30:00 GMT+0300(符合预期) - 1小时:
new Date(roundToNearest(Date.now(), 1000*60*60*1))→ Thu Sep 01 2022 05:00:00 GMT+0300(符合预期) - 2小时:
new Date(roundToNearest(Date.now(), 1000*60*60*2))→ Thu Sep 01 2022 03:00:00 GMT+0300(预期应为04:00:00,结果异常)
问题根源
Date.now()返回的是UTC时间戳(从1970-01-01 UTC开始的毫秒数),原函数直接对UTC时间戳做取整,但我们想要的是基于本地时区的时间间隔取整。
拿测试的2小时间隔举例:本地时间05:38对应的UTC时间是02:38,用2小时间隔对UTC时间戳取整得到00:00 UTC,转成本地时区就是03:00,和预期的本地时间04:00不符。短间隔(1小时内)因为时区偏移是整小时,刚好不会暴露这个问题,但长间隔就会出错。
修复方案一:修正时区偏移
通过将UTC时间戳转换为本地时间的等效UTC基准,取整后再还原时区偏移:
function roundToNearestLocal(value, interval) { const date = new Date(value); // 获取本地时区与UTC的偏移毫秒数(getTimezoneOffset返回分钟数,需转换) const timezoneOffset = date.getTimezoneOffset() * 60 * 1000; // 转换为本地时间的等效UTC时间戳,执行取整后再加回时区偏移 const localBaseTimestamp = value - timezoneOffset; const roundedLocalBase = Math.floor(localBaseTimestamp / interval) * interval; return roundedLocalBase + timezoneOffset; }
测试2小时间隔:new Date(roundToNearestLocal(Date.now(), 1000*60*60*2)) → Thu Sep 01 2022 04:00:00 GMT+0300(符合预期)
修复方案二:直接操作本地时间字段
如果觉得时区计算麻烦,也可以直接基于本地时间的小时、分钟来做取整,更直观:
function roundToNearestLocalAlt(value, interval) { const date = new Date(value); const intervalMinutes = interval / (1000 * 60); // 把间隔转成分钟数 // 计算本地时间的总分钟数 const totalLocalMinutes = date.getHours() * 60 + date.getMinutes(); // 向下取整到最近的间隔分钟数 const roundedTotalMinutes = Math.floor(totalLocalMinutes / intervalMinutes) * intervalMinutes; // 重置时分秒到取整后的时间 date.setHours(Math.floor(roundedTotalMinutes / 60)); date.setMinutes(roundedTotalMinutes % 60); date.setSeconds(0); date.setMilliseconds(0); return date.getTime(); }
这个方法直接修改Date对象的本地时间字段,同样能得到符合预期的结果,所有时间间隔测试都能正常工作。
内容的提问来源于stack exchange,提问作者Soggiorno
相关产品推荐
相关产品推荐

