前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库JavaScript Date 夏令时切换 时间运算问题
JavaScript数据处理

夏令时切换那天,用 Date 做时间计算会出什么问题?

夏令时开始那天,时钟从 01:59 直接跳到 03:00,02:30 这个本地时间根本不存在,new Date(2024, 2, 10, 2, 30) 不会报错,而是悄悄变成 03:30。结束那天 01:30 会出现两次,Date 默认取前一次。算持续时长用时间戳,算「明天同一钟点」要按日历走,两者不能混用。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数据处理
先看核心答案读代码示例
理解线索

本地钟点和时间点不总是一一对应

  1. 跳过的时段拨快时钟时,有一段本地时间在当地根本不存在
  2. 重复的时段拨慢时钟时,同一个钟点对应两个不同的时间点
  3. 时长与日历持续时长按毫秒加,日历日期按年月日推进

中国现在不用夏令时,本地开发很难发现这类 bug。但只要有海外用户,或者服务器跑在别的时区,问题就会出现在用户那边。

核心回答

先记住这个答案

夏令时切换会让本地时间出现断层和重叠。以纽约为例,2024 年 3 月 10 日凌晨时钟从 01:59 直接跳到 03:00,02:30 不存在,这时 new Date(2024, 2, 10, 2, 30) 不会报错,而是得到 03:30。11 月 3 日时钟从 01:59 拨回 01:00,01:30 出现两次,Date 取前一次。所以两类计算要分开:「过 24 小时」这种持续时长,直接在时间戳上加毫秒;「明天早上 9 点」这种日历时间,按年月日推进,再让时区规则去换算。

  • 春季拨快:一段本地时间不存在,Date 会往后挪
  • 秋季拨慢:同一钟点出现两次,Date 取较早那次
  • 加 24 小时和加一天,在切换那天会差 1 小时
  • 构造成功不代表时间存在,要回读字段核对

那一小时去哪了

夏令时就是夏天把时钟拨快一小时,冬天再拨回来。拨快的那一刻,墙上的钟跳过了一小时;拨回的那一刻,同一小时要走两遍。时间本身是连续的,断的是本地钟点。

用 UTC 时间点看纽约的钟JavaScript
const clock = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/New_York', hour: '2-digit', minute: '2-digit', hourCycle: 'h23'
})

// 春季:UTC 相差 30 分钟,纽约的钟却跳了 90 分钟
console.log(clock.format(new Date('2024-03-10T06:30:00Z')))
console.log(clock.format(new Date('2024-03-10T07:00:00Z')))
// 秋季:UTC 相差 1 小时,纽约的钟显示同一个时刻
console.log(clock.format(new Date('2024-11-03T05:30:00Z')))
console.log(clock.format(new Date('2024-11-03T06:30:00Z')))
查看输出与解释
01:30
03:00
01:30
01:30

前两行说明 02:00 到 02:59 在纽约那天不存在。后两行说明 01:30 那天出现了两次,第一次是夏令时的 01:30(UTC-4),第二次是标准时间的 01:30(UTC-5)。 所以把本地钟点换成时间戳时会碰到两种麻烦:遇到不存在的钟点,没有对应的时间戳;遇到重复的钟点,有两个候选。Date 的本地构造器对这两种情况各有固定处理:不存在的往后挪,重复的取较早那个。它不会报错,也不给你选择的机会。

加 24 小时和加一天不是一回事

这是业务里最容易出 bug 的地方。比如提醒功能要在「明天同一时间」再提醒一次,很多人直接写 time + 24 * 60 * 60 * 1000。平时没问题,碰上切换那天就会差一小时。

两种「明天」在切换那天分道扬镳JavaScript
// 以下注释是在 America/New_York 时区运行的结果
const start = new Date(2024, 2, 9, 9, 0) // 3 月 9 日 09:00,切换前一天

const plus24h = new Date(start.getTime() + 24 * 60 * 60 * 1000)
console.log(plus24h.getHours()) // 10,钟点变了

const nextDay = new Date(start)
nextDay.setDate(nextDay.getDate() + 1) // 按日历加一天
console.log(nextDay.getHours()) // 9,还是早上 9 点
console.log((nextDay - start) / 3600000) // 23,这一天只有 23 小时

两种写法都没错,回答的是不同的问题。「接口 24 小时后过期」「倒计时还剩多久」是持续时长,按毫秒加才准确。「每天早上 9 点提醒」「预约明天下午 3 点」是日历时间,要按年月日推进,让时区规则决定对应哪个时间戳。

日程类业务应该怎么存
预约、航班、排班这类数据,只存一个时间戳不够,还要存用户所在的 IANA 时区名,比如 America/New_York,最好连原始的日期和钟点一起存。原因是时区规则会变,各国政府会调整夏令时政策,未来某天的偏移今天未必能确定。有了时区名和本地钟点,到时候再按最新规则算时间戳就行。只存一次 getTimezoneOffset() 的结果,换季之后就错了。
回答前,多想一步

容易答错的地方

用固定 24 小时表示「明天同一时间」
跨过切换点时,本地的「明天同一钟点」可能只隔 23 小时,也可能隔 25 小时。先问清楚需求是持续时长还是日历时间,再决定是加毫秒还是加天数。
构造完只检查 isNaN
不存在的本地时间会被自动挪成一个有效的 Date,不会变成 Invalid Date,所以 isNaN(date.getTime()) 检查不出来。要确认用户输入的钟点真实存在,得把 getHours() 和 getMinutes() 读回来和输入比一下。
以为全部改成 UTC 就解决了
UTC 没有夏令时,做时间戳运算确实更安全。但用户要的是「当地每天 9 点」,这个 9 点属于某个时区,全换成 UTC 固定时刻后,换季时提醒就会变成当地 8 点或 10 点。
试着用自己的话回答

面试官还会怎么问?

秋季重复的两个 01:30,怎么让用户选?

旧的 Date API 表达不了这个选择,只给本地字段时总是取较早那个。能做的是让输入带上明确的偏移,比如 01:30-05:00,或者用支持歧义选项的库。新的 Temporal API 里 ZonedDateTime 有 disambiguation 参数,可以选 earlier 或 later,也可以直接让它报错。

测试夏令时的代码怎么写才不依赖开发机时区?

在 Node 里用 TZ=America/New_York 环境变量跑测试,或者在 Jest 配置里固定时区。测试样本挑切换点前后的时刻,春季和秋季各一组,同时断言时间戳差值和本地钟点,两个都对才算对。

用 dayjs 或 date-fns 能避开这个问题吗?

库本身不会让不存在的钟点变存在,它们帮的是把规则显式化。比如 dayjs 的 timezone 插件、date-fns-tz 都能按指定 IANA 时区做换算,并且区分加天数和加小时。前提还是得先想清楚业务要的是时长还是日历时间。

从一道题,走向一组知识

把知识连起来

数据处理

Date 对象里存的是时间戳还是本地时间?为什么换台电脑打印出来就不一样?

夏令时的问题只出在本地时间和时间戳互相换算这一步,那题讲 Date 为什么只存时间戳。

数据处理

setHours 和 setUTCHours 有什么区别?什么时候结果会不一样?

setHours 和 setUTCHours 在夏令时附近会差出一小时,是这题在 setter 上的具体表现。

参考资料

  • JavaScript:数据处理参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 那一小时去哪了
  3. 加 24 小时和加一天不是一回事
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑