JavaScript 实现北京时间精确到毫秒显示:UTC+8、Asia/Shanghai 与在线时间校准详解
在前端开发中,我们经常会遇到“显示当前时间”的需求。
如果只是简单显示本机时间,直接使用:
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
这也是“显示毫秒”和“真正实现高精度时间校准”之间最重要的区别。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)