前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 热点
旧版
首页程序员面试题库Date toISOString 与 toLocaleString 时区差异
JavaScript数据处理

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

toISOString() 永远按 UTC 输出,结尾的 Z 就是 UTC 的标记,北京时间早上 8 点会显示成 00:00Z。toLocaleString() 按运行环境的时区和语言输出给人看的文本。前者用来传数据,后者用来显示,两者存的是同一个时间点。

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

给机器看的和给人看的分开

  1. toISOString()固定 UTC、固定格式,适合接口传输、日志和 JSON
  2. toLocaleString()格式随语言变,时区随环境变,适合界面显示
  3. timeZone 选项显式指定要按哪个地区显示,不依赖设备默认时区

JSON.stringify 一个 Date 时调用的就是 toISOString(),所以接口里的时间默认都是 UTC。前端显示前要转成本地,而不是直接截字符串。

核心回答

先记住这个答案

toISOString() 输出的是 UTC 时间,格式固定为 YYYY-MM-DDTHH:mm:ss.sssZ,结尾的 Z 表示零时区。北京比 UTC 快 8 小时,所以北京时间早上 8 点打出来是 00:00:00.000Z,看起来像是少了 8 小时,其实是同一个时刻。toLocaleString() 则按运行环境的时区和语言,生成给人看的文本。它们各管一件事:toISOString() 格式稳定,用于接口、日志、存储;toLocaleString() 格式随环境变化,只用于界面显示。

  • toISOString() 固定 UTC,结尾 Z 表示零时区
  • toLocaleString() 按时区和语言输出,给人看
  • 用 toISOString() 截日期,早上 8 点前会少一天
  • 显示指定地区时间,显式传 timeZone

同一个时间点的三种输出

下面是一个 UTC 零点的 Date,分别用 ISO 格式、北京时间、纽约时间输出。

显式指定时区对比输出JavaScript
const instant = new Date('2026-09-10T00:00:00Z')

console.log(instant.toISOString()) // 永远是 UTC
console.log(instant.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai', hour12: false }))
console.log(instant.toLocaleString('zh-CN', { timeZone: 'America/New_York', hour12: false }))
console.log(JSON.stringify({ at: instant })) // JSON 里用的也是 toISOString
查看输出与解释
2026-09-10T00:00:00.000Z
2026/9/10 08:00:00
2026/9/9 20:00:00
{"at":"2026-09-10T00:00:00.000Z"}

三行显示完全不同,纽约那行连日期都是前一天,但 instant.getTime() 从头到尾没变过。这里特意传了 timeZone,如果不传,toLocaleString() 就用运行环境的默认时区,同一行代码在服务器和用户浏览器上结果不同。 最后一行说明一个很实用的事实:JSON.stringify 遇到 Date 会调用它的 toJSON(),而 toJSON() 内部调用的就是 toISOString()。所以接口里传的时间,默认都是 UTC 字符串。

最常见的 bug:用 toISOString() 截今天的日期

很多代码想拿「今天」的日期字符串,写成 new Date().toISOString().slice(0, 10)。白天测试一切正常,到了凌晨就出问题。

早上 8 点前截出来是昨天JavaScript
const morning = new Date('2026-09-10T07:00:00+08:00') // 北京早上 7 点

console.log(morning.toISOString().slice(0, 10)) // UTC 还是 9 号晚上
console.log(morning.toLocaleDateString('en-CA', { timeZone: 'Asia/Shanghai' }))
查看输出与解释
2026-09-09
2026-09-10

北京早上 7 点,UTC 还是前一天 23 点,截出来就是 9 号。国内用户在凌晨 0 点到 8 点之间操作,日期全部少一天,默认日期选择器、签到、日报这类功能都会中招。 正确的做法是按用户时区格式化。en-CA 这个语言的日期格式正好是 YYYY-MM-DD,配合 timeZone 就能拿到本地日期。更稳的写法是 Intl.DateTimeFormat 的 formatToParts(),按年月日片段自己拼,不依赖某个语言的格式恰好长什么样。

为什么不能反过来解析 toLocaleString()
toLocaleString() 的输出是给人看的,格式会随语言、浏览器版本、ICU 数据变化。比如英文的时间里可能带不换行空格,阿拉伯语的数字可能不是 0~9。把它存进数据库、再用 new Date() 解析回来,换个环境就解析失败。存储和传输一律用 toISOString() 或时间戳,显示的时候再格式化。
回答前,多想一步

容易答错的地方

把 toISOString() 的结果直接显示给用户
结尾的 Z 明确表示 UTC。直接显示在国内用户面前,小时会比本地少 8,看起来像 bug。显示前要用 toLocaleString() 或 Intl.DateTimeFormat 转成本地时间。
以为 toISOString() 会带上本地偏移
它不会输出 +08:00,永远是 Z。想要带本地偏移的 ISO 字符串,得自己用 getTimezoneOffset() 拼,或者用 dayjs 这类库的 format()。
试着用自己的话回答

面试官还会怎么问?

只想显示某个时区的年月日,怎么写?

用 toLocaleDateString() 或 Intl.DateTimeFormat,显式传 timeZone,再按需要传 year、month、day。列表里大量格式化时,建一个 Intl.DateTimeFormat 实例复用,比每次调 toLocaleString() 快。

SSR 页面里显示时间为什么会出现 hydration 报错?

服务端默认时区通常是 UTC,用户浏览器是东八区,两边各自 toLocaleString() 得到的文本不同,React 对比时就报不匹配。解决办法是渲染时显式传用户时区,或者时间部分只在客户端渲染。

toISOString() 什么时候会抛错?

Date 无效的时候。new Date('abc').toISOString() 抛 RangeError,而 toLocaleString() 只会返回 Invalid Date 字符串。所以序列化前最好先用 Number.isNaN(date.getTime()) 检查一下。

从一道题,走向一组知识

把知识连起来

数据处理

文件开头带 BOM 时,TextDecoder 会怎么处理?ignoreBOM 是什么意思?

都是在数据边界上处理「格式约定」,一个约定时间用 UTC 写,一个约定文本开头的 BOM 怎么处理。

数据处理

中文名字用 sort() 排出来乱七八糟,怎么按拼音或语言习惯排序?

toLocaleString() 背后是 Intl.DateTimeFormat,而 localeCompare 背后是 Intl.Collator,都是按语言规则处理给人看的内容。

参考资料

  • JavaScript:数据处理参考资料

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

本题目录
  1. 先记住这个答案
  2. 同一个时间点的三种输出
  3. 最常见的 bug:用 toISOString() 截今天的日期
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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