先记住这个答案
date.getTimezoneOffset() 返回的是 UTC 时间减去本地时间的分钟数。北京是 UTC+8,本地比 UTC 快 480 分钟,UTC 减本地就是 -480。所以记住两点:单位是分钟,不是小时;符号和 UTC+8 的写法相反,本地比 UTC 快就是负数,比 UTC 慢就是正数。另外它是按调用的那个 Date 算的,纽约冬天返回 300,夏天返回 240,不能当成用户的固定属性缓存起来。
- 单位是分钟,东八区返回 -480
- 符号和 UTC+8 这种写法相反
- 有夏令时的地区,不同日期返回值不同
- 拿时区名要用
Intl,不能靠偏移推断
冬天和夏天调用结果不同
很多人以为 getTimezoneOffset() 是「用户时区的偏移」,其实它是「这台机器在这个时刻的偏移」。换个日期调用,结果可能就变了。
const winter = new Date('2026-01-15T12:00:00Z')
const summer = new Date('2026-07-15T12:00:00Z')
// 在东八区(Asia/Shanghai)运行:中国没有夏令时
winter.getTimezoneOffset() // -480
summer.getTimezoneOffset() // -480
// 在 America/New_York 运行:夏天用夏令时,快了一小时
winter.getTimezoneOffset() // 300,即 UTC-5
summer.getTimezoneOffset() // 240,即 UTC-4纽约冬天比 UTC 慢 5 小时,UTC 减本地是正的 300 分钟。夏天拨快一小时后,只慢 4 小时,变成 240。
所以页面启动时读一次偏移,然后拿它去换算全年的时间,在有夏令时的地区一定会错一半。每个时间点要用它自己那个 Date 去调用,或者干脆交给 Intl.DateTimeFormat 按时区名处理。
还有一点:结果只看运行环境的时区,和构造 Date 时写的偏移无关。new Date('2026-09-10T08:00:00+09:00').getTimezoneOffset() 在北京的机器上跑,返回的还是 -480,而不是东京的 -540。
把它格式化成 UTC+08:00
要在界面上显示「UTC+08:00」这种格式,先把符号翻过来,再拆成小时和分钟。别直接除以 60 就完事,世界上还有半小时和 45 分钟的时区。
function formatOffset(offset) {
// offset 是 getTimezoneOffset() 的返回值
const minutes = -offset // 翻转成「本地减 UTC」
const sign = minutes >= 0 ? '+' : '-'
const abs = Math.abs(minutes)
const hh = String(Math.floor(abs / 60)).padStart(2, '0')
const mm = String(abs % 60).padStart(2, '0')
return `UTC${sign}${hh}:${mm}`
}
console.log(formatOffset(-480)) // 北京
console.log(formatOffset(300)) // 纽约冬天
console.log(formatOffset(-330)) // 印度
console.log(formatOffset(-345)) // 尼泊尔查看输出与解释
UTC+08:00
UTC-05:00
UTC+05:30
UTC+05:45印度是 UTC+5:30,尼泊尔是 UTC+5:45。如果只写 offset / 60,印度会显示成 -5.5,符号错了,格式也不对。
- 为什么这个方法要设计成反的
getTimezoneOffset()的含义是「本地时间加上这个数就得到 UTC」。北京时间 08:00 加上 -480 分钟,就是 UTC 的 00:00。这个方向在做换算时是顺的,只是和人们平时说的 UTC+8 反了。记不住的话,用北京举例推一遍就行:北京快,UTC 减北京是负数。
容易答错的地方
- 以为东八区返回 480 或者 8
- 单位是分钟,方向是 UTC 减本地。东八区返回 -480,展示成 UTC+8 时要先取负再除以 60。
- 用偏移值推断用户所在地
- 同一个偏移对应很多地区。-480 可能是北京,也可能是新加坡、珀斯。这些地方现在偏移一样,历史规则和未来政策却不一定一样。要知道用户的时区,应该拿时区名,而不是偏移。
面试官还会怎么问?
怎么拿到用户时区的名字?
Intl.DateTimeFormat().resolvedOptions().timeZone,返回 Asia/Shanghai、America/New_York 这种 IANA 名称。它反映的是浏览器或系统设置,用户可能在出差,涉及排期的功能最好让用户确认一下。
服务端和浏览器拿到的偏移为什么不一样?
getTimezoneOffset() 读的是运行环境的时区。服务器容器通常设成 UTC,返回 0;用户浏览器在北京,返回 -480。SSR 页面里用它算出来的时间,在服务端和客户端就对不上,会导致 hydration 报错。
要保存用户的时区设置,存偏移还是存时区名?
存时区名。偏移只描述某一个时刻,夏令时一切换就过期了。存了 America/New_York,任何时候都能按当时的规则算出正确的偏移;存了 -300,到了夏天就差一小时。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。