前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 setHours与setUTCHours区别
JavaScript数据处理

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

setHours 改的是本地时间的小时,改完再按本地时区换算回时间戳;setUTCHours 直接改 UTC 的小时。在东八区,setHours(0) 得到北京零点,setUTCHours(0) 得到北京早上 8 点。碰上夏令时切换,本地加 2 小时实际可能过了 3 小时。

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

改的是哪块表上的钟点

  1. setHours改本地钟点,再按当地时区规则换回时间戳,会受夏令时影响
  2. setUTCHours改 UTC 钟点,UTC 没有夏令时,时间轴是连续的
  3. 原地修改两个方法都改调用它的那个 Date,并返回新的毫秒数

只是想加一段固定时长,比如 90 分钟后过期,直接在 getTime() 上加毫秒最清楚,不用去碰任何小时字段。

核心回答

先记住这个答案

Date 内部只有一个时间戳,setHours 和 setUTCHours 都是改完某个字段后重新算这个时间戳,区别在于改的是哪块表。setHours 先把时间戳换成本地钟点,改小时,再按本地时区换回去;setUTCHours 在 UTC 钟点上改,不经过本地时区。所以在东八区把同一个时间设成 0 点,两者差 8 小时。在有夏令时的地区,setHours 还可能碰上某个钟点不存在或出现两次,改出来的时间差和字段差对不上。

  • setHours 改本地钟点,setUTCHours 改 UTC 钟点
  • 东八区里两者设成 0 点,结果差 8 小时
  • 跨夏令时,本地加 2 小时不一定等于过 2 小时
  • setter 原地修改 Date,返回的是时间戳不是 Date

最常见的场景:把时间设成当天零点

「查今天的订单」「按天统计」都要先算出当天零点。很多人随手写 setUTCHours(0, 0, 0, 0),在国内就会出问题。

东八区里两种零点差 8 小时JavaScript
// 以下注释是在东八区(Asia/Shanghai)运行的结果
const now = new Date('2026-09-10T15:30:00+08:00') // 北京下午 3 点半

const local = new Date(now)
local.setHours(0, 0, 0, 0) // 北京时间 9 月 10 日 00:00
console.log(local.toISOString()) // 2026-09-09T16:00:00.000Z

const utc = new Date(now)
utc.setUTCHours(0, 0, 0, 0) // UTC 的 9 月 10 日 00:00
console.log(utc.toString()) // Thu Sep 10 2026 08:00:00 GMT+0800

setHours(0, 0, 0, 0) 得到的是北京的零点,换成 UTC 是前一天 16:00。setUTCHours(0, 0, 0, 0) 得到的是 UTC 零点,在北京已经是早上 8 点。如果你拿后者去查「今天」的数据,凌晨 0 点到 8 点下的单全都漏掉了。 更隐蔽的是,如果当前时间是北京早上 5 点,这时 UTC 还是前一天,setUTCHours(0) 会得到前一天早上 8 点,连日期都错了。按用户的「今天」算,用 setHours;按 UTC 日期算,比如和后端约定了 UTC 日切,才用 setUTCHours。

跨夏令时,本地加 2 小时不等于过 2 小时

东八区没有夏令时,上面的差距是固定的 8 小时。在有夏令时的地区,setHours 还会多一层麻烦。纽约 2024 年 11 月 3 日凌晨 2 点时钟拨回 1 点,01:00 到 01:59 走了两遍。

同样加 2 小时,实际过了多久JavaScript
// 以下注释是在 America/New_York 时区运行的结果
const start = new Date('2024-11-03T00:30:00-04:00') // 本地 00:30
const local = new Date(start)
const utc = new Date(start)

local.setHours(local.getHours() + 2) // 本地钟点改成 02:30
utc.setUTCHours(utc.getUTCHours() + 2) // UTC 钟点加 2

console.log((local - start) / 3600000) // 3
console.log((utc - start) / 3600000) // 2

本地钟面从 00:30 走到 02:30,中间 01:00 到 02:00 这一段走了两遍,所以实际过了 3 小时。setUTCHours 在没有夏令时的 UTC 时间轴上加 2,严格过了 2 小时,只是本地钟面显示成了 01:30。 两个结果都没错,回答的是不同问题。缓存 TTL、倒计时要的是真实经过的时长,用时间戳或 UTC 方法。「每天早上 9 点」这种排班要的是本地钟点,用 setHours 或 setDate。

两个方法共同的坑:原地修改和返回值

setHours 和 setUTCHours 都会直接改调用它的那个对象,返回值是新的毫秒时间戳。这两点在 React 状态、函数参数里很容易出事。

返回的是数字,原对象已经被改了JavaScript
const base = new Date('2026-09-10T00:00:00Z')
const ret = base.setUTCHours(25) // 25 点会进位到第二天 1 点

console.log(typeof ret, ret === base.getTime()) // 返回值是时间戳
console.log(base.toISOString()) // 原对象已经变了
查看输出与解释
number true
2026-09-11T01:00:00.000Z

ret 是数字,拿它继续调 .toISOString() 会报错。base 本身被改了,如果它是函数参数或者 React state 里的对象,调用方手里的日期也跟着变了。需要保留原值时,先用 new Date(base) 复制一份再改。另外可以看到,传 25 不会报错,会进位成第二天的 1 点。

回答前,多想一步

容易答错的地方

以为加 1 小时永远等于加 3600000 毫秒
用 setUTCHours 或直接加毫秒时成立。用 setHours 跨过夏令时切换点时就不一定了。比如秋季回拨那天,本地 01:30 是夏令时的那一次时,把钟点改成 2 点,实际过了 2 小时。
以为东八区用 setUTCHours(0) 也能拿到今天零点
拿到的是北京早上 8 点,凌晨时段还可能落到前一天。按用户本地日期算,要用 setHours(0, 0, 0, 0)。
试着用自己的话回答

面试官还会怎么问?

怎么给一个时间加 90 分钟?

new Date(date.getTime() + 90 * 60 * 1000)。直接在时间戳上加,表达的就是「经过 90 分钟」,不受本地时区和夏令时影响,也不会改原对象。

怎么拿到用户时区里的「明天同一时间」?

复制一份,然后 setDate(d.getDate() + 1)。它按本地日历加一天,钟点保持不变,跨月、跨年会自动进位。碰上夏令时切换,这一天可能是 23 或 25 小时,这正是日历语义要的结果。

setHours 能一次设置分钟和秒吗?

能。完整签名是 setHours(hours, minutes, seconds, ms),后三个可选。setHours(0, 0, 0, 0) 一次把时分秒毫秒都清零,比连调四个 setter 简洁,setUTCHours 也一样。

从一道题,走向一组知识

把知识连起来

数据处理

getTimezoneOffset 在北京为什么返回 -480,而不是 8?

两个 setter 设成同一个钟点时差出来的那段时间,正好就是 getTimezoneOffset() 返回的偏移。

数据处理

为什么 toISOString 打出来的时间比北京时间少 8 小时,toLocaleString 却是对的?

用 setUTCHours 改完再用 toISOString() 打印,是检查 UTC 字段最直接的办法,那题讲两种输出的差别。

参考资料

  • JavaScript:数据处理参考资料

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

本题目录
  1. 先记住这个答案
  2. 最常见的场景:把时间设成当天零点
  3. 跨夏令时,本地加 2 小时不等于过 2 小时
  4. 两个方法共同的坑:原地修改和返回值
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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