如何实现通用夏令时(DST)校验函数,解决CI环境运行失败问题
问题根源
你当前的代码出现本地运行正常、CI失败的核心原因是:原生Date.prototype.getTimezoneOffset()方法返回的是代码运行环境本地时区相对于UTC的偏移量,和你用toDate指定的时区完全无关。你本地环境时区恰好是Europe/Amsterdam所以测试通过,CI环境默认时区通常为UTC,自然返回错误结果。
解决方案
调整isDST函数,增加时区入参,使用date-fns-tz提供的tzOffset方法计算指定时区的偏移量,完全脱离运行环境时区的影响。
完整修改后代码
import { toDate, tzOffset } from "date-fns-tz" import { parseISO, getYear } from "date-fns" /** * 校验指定时区下的给定日期是否处于夏令时 * @param {Date|string|number} date 待校验的日期 * @param {string} timeZone 目标时区IANA标识,例如 Europe/Amsterdam * @returns {boolean} 目标日期在指定时区是否处于夏令时 */ export function isDST(date, timeZone) { const year = getYear(date) // 计算指定时区当年1月1日的偏移量 const januaryOffset = tzOffset(timeZone, new Date(year, 0, 1)) // 计算指定时区当年7月1日的偏移量 const julyOffset = tzOffset(timeZone, new Date(year, 6, 1)) // 计算指定时区下待校验日期的偏移量 const currentOffset = tzOffset(timeZone, date) // 偏移量最大值对应冬令时,二者不等则为夏令时 return Math.max(januaryOffset, julyOffset) !== currentOffset } // 调整后的测试用例 it("returns true if dst applies", () => { const targetTz = "Europe/Amsterdam" const date = toDate(parseISO("2021-03-28 02:00:00"), { timeZone: targetTz, }) expect(isDST(date, targetTz)).toEqual(true) }) it("returns false if dst does not apply", () => { const targetTz = "Europe/Amsterdam" const date = toDate(parseISO("2021-10-31 03:00:00"), { timeZone: targetTz, }) expect(isDST(date, targetTz)).toEqual(false) })
说明
- 调整后的函数为通用实现,传入任意IANA标准时区标识即可校验对应时区的夏令时状态,不受运行环境时区影响,CI环境可以正常通过测试。
- 如果你固定使用某一个时区,也可以给
isDST的timeZone参数设置默认值,无需每次调用都传参。
内容的提问来源于stack exchange,提问作者user15485638
相关产品推荐
相关产品推荐

