在前端开发中,我们经常会遇到“显示当前时间”的需求。

如果只是简单显示本机时间,直接使用:

new Date()

就可以完成。

但如果需求变成:

  • 显示北京时间

  • 精确到毫秒

  • 不受用户电脑时区影响

  • 支持在线校准

  • 需要全屏显示

  • 希望与标准时间进行对比

事情就没有看起来那么简单了。

本文从 JavaScript 实现角度,介绍如何在网页中显示精确到毫秒的北京时间,并解释 UTC+8、Asia/Shanghai、本地时间误差以及在线时间校准的基本原理。

如果只是需要快速查看当前北京时间,也可以直接使用:

北京时间精确到毫秒在线工具:

北京时间 - 毫秒级校准与世界时区对照


一、北京时间到底是什么?

北京时间是中国采用的标准时间。

它对应的 UTC 时差为:

UTC+8

也就是说:

北京时间 = UTC 时间 + 8 小时

例如:

UTC 时间:      03:00:00
北京时间:      11:00:00

需要注意的是,“北京时间”虽然名称中包含“北京”,但并不是只供北京市使用。

中国大陆统一使用 UTC+8 作为标准时间。


二、JavaScript 中的 Date 为什么可能不是北京时间?

JavaScript 中获取当前时间最简单的方法是:

const now = new Date();

console.log(now);

问题在于:

Date 对象本身保存的是时间戳,但是在格式化时通常会根据用户设备当前所在时区显示。

例如用户电脑位于美国:

new Date().toLocaleString();

显示的可能是美国当地时间,而不是北京时间。

因此,如果你的网页明确要求显示北京时间,就不应该简单依赖用户电脑的本地时区。


三、推荐使用 Asia/Shanghai 时区

现代浏览器提供了 Intl.DateTimeFormat API,可以明确指定时区。

例如:

const formatter = new Intl.DateTimeFormat('zh-CN', {
  timeZone: 'Asia/Shanghai',
  year: 'numeric',
  month: '2-digit',
  day: '2-digit',
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit',
  hour12: false
});

console.log(formatter.format(new Date()));

这里最关键的是:

timeZone: 'Asia/Shanghai'

Asia/Shanghai 是 IANA 时区数据库中用于表示中国标准时间的时区名称。

相比直接手动计算:

UTC + 8

使用 IANA 时区名称通常更加规范。


四、如何显示精确到毫秒的北京时间?

Intl.DateTimeFormat 可以方便地格式化年月日、时分秒。

但是如果需要显示毫秒,可以直接从 Date 对象中获取:

const now = new Date();

const milliseconds = now.getMilliseconds();

console.log(milliseconds);

不过这里还有一个问题。

getMilliseconds() 本身是当前设备时间对应的毫秒部分。

对于北京时间显示来说,毫秒本身并不会因为时区改变,因为时区只会改变小时数。

因此我们可以把北京时间的时分秒和当前毫秒组合起来。

例如:

function getBeijingTime() {
  const now = new Date();

  const formatter = new Intl.DateTimeFormat('zh-CN', {
    timeZone: 'Asia/Shanghai',
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false
  });

  const milliseconds = String(
    now.getMilliseconds()
  ).padStart(3, '0');

  return `${formatter.format(now)}.${milliseconds}`;
}

console.log(getBeijingTime());

输出类似:

2026/08/24 11:46:32.381

这样就完成了一个基础的北京时间毫秒显示。


五、为什么毫秒必须补 0?

getMilliseconds() 返回值范围是:

0 ~ 999

例如:

new Date().getMilliseconds()

可能返回:

7

但正常时间显示应该是:

007

而不是:

7

因此通常需要:

String(milliseconds).padStart(3, '0')

例如:

String(7).padStart(3, '0');

结果:

007

六、使用 requestAnimationFrame 实现流畅刷新

如果需要制作一个实时在线时钟,很多人第一反应是:

setInterval(() => {
  // 更新时间
}, 1);

理论上看,1 毫秒刷新一次似乎很适合毫秒时钟。

实际上并不建议这样做。

浏览器并不能保证 setInterval(..., 1) 每 1 毫秒执行一次。

JavaScript 主线程还有:

  • 页面渲染

  • 网络请求

  • 用户交互

  • DOM 更新

  • 浏览器任务调度

因此真正执行间隔通常远大于 1ms。

更合理的方式之一是使用:

requestAnimationFrame()

例如:

<div id="clock"></div>

JavaScript:

const clock = document.getElementById('clock');

function updateClock() {
  const now = new Date();

  const formatter = new Intl.DateTimeFormat('zh-CN', {
    timeZone: 'Asia/Shanghai',
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false
  });

  const milliseconds = String(
    now.getMilliseconds()
  ).padStart(3, '0');

  clock.textContent =
    `${formatter.format(now)}.${milliseconds}`;

  requestAnimationFrame(updateClock);
}

updateClock();

这样浏览器通常会按照屏幕刷新频率更新时间。

例如:

60Hz
120Hz
144Hz

虽然视觉上不是每一毫秒都真正重绘一次,但对于网页时钟已经足够流畅。


七、一个更适合实际项目的写法

为了避免每帧都重新创建 Intl.DateTimeFormat,可以提前创建格式化器。

const formatter = new Intl.DateTimeFormat('zh-CN', {
  timeZone: 'Asia/Shanghai',
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit',
  hour12: false
});

function formatMilliseconds(value) {
  return String(value).padStart(3, '0');
}

function updateClock() {
  const now = new Date();

  const time = formatter.format(now);

  const milliseconds =
    formatMilliseconds(now.getMilliseconds());

  document.getElementById('clock').textContent =
    `${time}.${milliseconds}`;

  requestAnimationFrame(updateClock);
}

updateClock();

页面效果类似:

11:46:35.286

如果再配合较大的字体,就可以制作一个简单的全屏北京时间页面。


八、显示日期和星期

实际在线时钟通常不仅显示:

11:46:35.286

还会显示:

2026年8月24日 星期一

可以分别格式化。

例如:

const dateFormatter = new Intl.DateTimeFormat('zh-CN', {
  timeZone: 'Asia/Shanghai',
  year: 'numeric',
  month: 'long',
  day: 'numeric',
  weekday: 'long'
});

console.log(
  dateFormatter.format(new Date())
);

输出类似:

2026年8月24日星期一

九、为什么用户电脑时间可能不准确?

到这里还有一个非常关键的问题:

new Date()

得到的时间从哪里来?

答案是:

用户设备系统时间。

也就是说,如果用户电脑本身时间慢了 20 秒:

系统时间:
11:40:00

真实时间:
11:40:20

JavaScript 获取的仍然可能是:

11:40:00

因此:

显示到毫秒

和:

准确到毫秒

并不是一回事。

这一点非常重要。


十、“精确到毫秒”与“准确到毫秒”有什么区别?

两者很容易被混淆。

精确到毫秒

指显示格式包含毫秒:

11:46:32.385

即:

HH:mm:ss.SSS

这是显示精度。


准确到毫秒

则意味着显示时间与标准时间的误差非常小。

例如:

标准时间:
11:46:32.385

设备时间:
11:46:32.382

误差只有:

3ms

这涉及:

  • 服务器时间

  • 网络延迟

  • NTP

  • 请求往返时间

  • 浏览器执行延迟

  • 操作系统时钟

实现难度明显更高。

所以一个网页能够显示:

123 毫秒

不代表它本身真的拥有毫秒级授时精度。


十一、什么是 NTP?

NTP 全称:

Network Time Protocol

中文通常称为:

网络时间协议

操作系统会通过网络时间服务器同步设备时间。

Windows、Linux、macOS、手机系统都会使用类似机制维护系统时间。

所以多数情况下:

new Date()

已经比较接近真实时间。

但仍然可能因为:

  • 用户关闭自动同步

  • 系统时钟漂移

  • 网络异常

  • 长时间未同步

产生误差。


十二、网页如何实现在线时间校准?

比较常见的方法是:

浏览器
   ↓
请求服务器
   ↓
获取服务器时间
   ↓
计算网络延迟
   ↓
估算时间差值
   ↓
本地持续运行时钟

例如服务器返回:

{
  "timestamp": 1787543200123
}

浏览器记录:

const requestStart = Date.now();

服务器响应后:

const requestEnd = Date.now();

可以简单估算网络往返耗时:

const rtt = requestEnd - requestStart;

如果假设请求和响应耗时大致对称,可以估算:

const networkDelay = rtt / 2;

进而估算收到响应时的服务器时间:

const correctedServerTime =
  serverTimestamp + networkDelay;

然后计算设备时间差:

const offset =
  correctedServerTime - Date.now();

以后显示时间时:

const correctedTime =
  Date.now() + offset;

这样即使用户本地系统时间存在一定偏差,也可以通过服务器时间进行修正。


十三、为什么不能直接请求一次服务器时间就结束?

因为网络请求本身存在延迟。

例如:

请求发送:
11:00:00.000

服务器返回:
11:00:00.100

浏览器收到:
11:00:00.200

如果直接使用服务器返回时间:

11:00:00.100

那么浏览器收到时实际上已经过去约:

100ms

所以更加完善的时间同步算法通常需要考虑:

RTT

也就是:

Round Trip Time

请求往返时间。

有些系统还会:

请求多次
↓
去掉异常值
↓
计算平均延迟
↓
计算服务器与设备的时间偏移

这样结果通常更加稳定。


十四、为什么北京时间一般使用 Asia/Shanghai?

很多开发者第一次看到都会疑惑:

北京时间为什么不是 Asia/Beijing?

这是因为 IANA Time Zone Database 中,中国大陆常用的时区标识是:

Asia/Shanghai

因此 JavaScript 中通常使用:

timeZone: 'Asia/Shanghai'

例如:

new Intl.DateTimeFormat('zh-CN', {
  timeZone: 'Asia/Shanghai'
}).format(new Date());

不要自行创造:

Asia/Beijing

否则浏览器可能直接报错:

RangeError: Invalid time zone specified

十五、为什么不建议直接手动加 8 小时?

有一种常见写法:

const beijingTime =
  new Date(Date.now() + 8 * 60 * 60 * 1000);

看起来简单。

但这种写法很容易与:

  • 当前系统时区

  • UTC 格式化

  • Date 的本地格式化行为

混在一起,最终出现重复偏移。

例如开发者可能先:

+8 小时

随后又按本地时区格式化。

这样就容易出现错误。

所以在现代浏览器中,更推荐:

Intl.DateTimeFormat

配合:

Asia/Shanghai

明确指定目标时区。


十六、一个完整的北京时间页面示例

HTML:

<div class="clock-box">
  <div id="time"></div>
  <div id="date"></div>
</div>

CSS:

.clock-box {
  text-align: center;
  font-family: Arial, sans-serif;
}

#time {
  font-size: 64px;
  font-weight: 700;
}

#date {
  margin-top: 16px;
  font-size: 20px;
}

JavaScript:

const timeFormatter =
  new Intl.DateTimeFormat('zh-CN', {
    timeZone: 'Asia/Shanghai',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false
  });

const dateFormatter =
  new Intl.DateTimeFormat('zh-CN', {
    timeZone: 'Asia/Shanghai',
    year: 'numeric',
    month: 'long',
    day: 'numeric',
    weekday: 'long'
  });

function updateBeijingTime() {
  const now = new Date();

  const time =
    timeFormatter.format(now);

  const milliseconds =
    String(now.getMilliseconds())
      .padStart(3, '0');

  document.getElementById('time')
    .textContent =
      `${time}.${milliseconds}`;

  document.getElementById('date')
    .textContent =
      dateFormatter.format(now);

  requestAnimationFrame(
    updateBeijingTime
  );
}

updateBeijingTime();

最终效果:

11:46:35.286

2026年8月24日 星期一

十七、实际可以用在哪些地方?

北京时间毫秒显示不仅适合普通时钟。

还可以用于:

1. 抢购倒计时

例如:

秒杀
抢票
限时活动

2. 系统运维

核对:

日志时间
服务器时间
客户端时间

3. API 调试

查看:

请求时间戳
接口签名
Token 过期时间

4. 数据同步

例如:

前端埋点
BI 数据
日志采集
订单时间

5. 大屏展示

可以制作:

全屏北京时间
会议室时钟
监控中心时钟
直播计时

十八、在线查看北京时间

如果只是为了查看:

  • 当前北京时间

  • 精确到毫秒

  • UTC+8

  • 当前日期

  • 在线校准

  • 世界时区信息

可以直接使用:

MapChaxun 北京时间在线工具:

北京时间 - 毫秒级校准与世界时区对照

页面可以直接查看当前北京时间,也适合作为开发过程中核对时间的辅助工具。


十九、常见问题

北京时间是 UTC+8 吗?

是。

北京时间采用:

UTC+8

JavaScript 的 Date 是北京时间吗?

不一定。

Date 保存时间戳,但显示结果通常受到当前设备时区影响。

如果明确需要北京时间,建议指定:

timeZone: 'Asia/Shanghai'

JavaScript 可以精确显示到毫秒吗?

可以。

可以通过:

getMilliseconds()

取得毫秒部分。


显示毫秒就代表时间准确到毫秒吗?

不是。

显示精度与实际授时精度是两个概念。


为什么系统时间和在线北京时间不同?

可能原因包括:

系统时间未同步
电脑时钟漂移
网络延迟
NTP 同步异常
用户手动修改时间

二十、总结

使用 JavaScript 实现北京时间并不复杂。

最基本的思路是:

Date
  ↓
Intl.DateTimeFormat
  ↓
Asia/Shanghai
  ↓
获取时分秒
  ↓
拼接 milliseconds
  ↓
requestAnimationFrame 刷新

如果只是需要显示:

北京时间精确到毫秒

前端完全可以实现。

但如果需要进一步做到:

在线校准
设备时间差
标准时间同步

就必须考虑:

服务器时间
网络延迟
RTT
时间偏移
NTP

这也是“显示毫秒”和“真正实现高精度时间校准”之间最重要的区别。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐