在前端显示当前日期和时间,主要有以下几种方法,从原生的 JavaScript 到成熟的第三方库,各有适用场景:

🛠️ 原生 JavaScript (无需外部依赖)

这是最基础、直接的方式,适用于简单需求。

  • new Date():创建一个表示当前时间的 Date 对象。
  • Date.now():获取当前时间的时间戳(毫秒数),适合用于计算时间差或记录时间点。

拿到 Date 对象后,可以通过其内置方法获取具体数值,再拼接成想要的格式。例如:

const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始
// ... 获取日、时、分、秒
const formatted = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;

Date 对象也自带了一些格式化方法,如 toLocaleString()toDateString()等,可直接使用。

🚀 第三方库 (功能强大,推荐)

对于复杂的时间处理、格式化、时区转换等,使用成熟的库能极大提升开发效率。

  • Day.js极力推荐。仅 2KB 左右,极其轻量。API 与 Moment.js 高度相似,上手简单,是现代项目的首选。
  • Moment.js:曾经的行业标准,功能全面。但因其体积较大且设计上有些过时,官方已不建议在新项目中使用。
  • date-fns:一个模块化的库,你可以按需引入函数,有助于减小打包体积。

使用示例 (Day.js)

import dayjs from 'dayjs';
const formatted = dayjs().format('YYYY-MM-DD HH:mm:ss'); 

⚛️ 在主流框架中的实践

在 React、Vue 等框架中,结合生命周期和状态管理来实现动态显示:

  • Vue:在 data 中定义变量,在 mounted 钩子中初始化并利用 setInterval 定时更新。模板中直接绑定变量即可。
  • React:在函数组件中使用 useState 存储时间,useEffect 设置定时器,并用 useMemo 优化性能。在类组件的 render 方法中直接调用格式化方法。
  • 通用原则:核心都是利用 setInterval 每秒更新一次状态,驱动视图刷新。

💎 其他方法

  • Intl.DateTimeFormat:浏览器内置的国际化API,能提供更精细的本地化时间格式化控制。
  • UI组件库:一些UI库(如 vue-datepicker)也提供了封装好的日期时间相关组件。

简单展示用原生JS即可,复杂场景推荐 Day.js。在框架中使用时,记得结合 setInterval 实现动态更新。

显示“运行时间段”本质是计算时间差(持续时间)并动态刷新,和显示“当前时间点”逻辑完全不同。核心是记录起始时间戳,用当前时间戳减去它,再格式化展示。

这里有几种实现方式,从基础到进阶:

1. 原生 JS 核心逻辑(手动计算)

这是最底层的方案,关键在于将毫秒差转换为“时:分:秒”:

const startTime = Date.now(); // 记录开始时刻

function updateDuration() {
  const elapsed = Date.now() - startTime; // 获取毫秒差
  const seconds = Math.floor(elapsed / 1000) % 60;
  const minutes = Math.floor(elapsed / (1000 * 60)) % 60;
  const hours = Math.floor(elapsed / (1000 * 60 * 60));
  // 补零后拼接显示,例如 01:23:45
  console.log(`${pad(hours)}:${pad(minutes)}:${pad(seconds)}`);
}
// 配合 setInterval(() => updateDuration(), 1000) 每秒刷新

注意:务必用 Date.now() 实时计算差值,不要在定时器里累加秒数(seconds++),因为浏览器切后台会导致定时器延迟,累加会不准。

2. 使用 Day.js 的 Duration 插件(推荐)

原生计算进位比较繁琐,用库最省心:

import dayjs from 'dayjs';
import duration from 'dayjs/plugin/duration';
dayjs.extend(duration);

const start = dayjs();
setInterval(() => {
  const diff = dayjs().diff(start); // 毫秒差
  const dur = dayjs.duration(diff);
  // 格式化为 时:分:秒,超过24小时会自动进位
  console.log(dur.format('HH:mm:ss')); 
}, 1000);

如果需要显示“X天X小时”这种人性化文本,直接用 dur.humanize() 即可。

3. 框架中的实践(以 React 为例)

在组件里要特别注意清理定时器,防止内存泄漏:

function Timer() {
  const [duration, setDuration] = useState(0);
  const startTimeRef = useRef(Date.now());

  useEffect(() => {
    const timer = setInterval(() => {
      setDuration(Date.now() - startTimeRef.current);
    }, 1000);
    return () => clearInterval(timer); // 必须清理
  }, []);

  return <div>{formatDuration(duration)}</div>; // formatDuration 复用原生逻辑
}

(Vue 同理,在 onBeforeUnmount 中清除 setInterval

4. 进阶技巧:刷新页面保持连续性

如果刷新页面想接着算,不能只存内存,需要借助 localStorage

// 页面加载时读取存储的开始时间
const startTime = localStorage.getItem('appStart') || Date.now();
localStorage.setItem('appStart', startTime);
// 之后计算差值时基于这个持久化的时间戳

5. 应对“切后台”的优化

浏览器切后台时 setInterval 会被减速。如果不要求绝对精准(比如不涉及计费),默认方案即可;若要求极高精度,可结合 requestAnimationFrameWeb Worker,但通常代价较大,很少在普通页面中使用。


总结方案选择:

  • 简单场景:直接用原生 Date.now() 计算差值。
  • 复杂格式化:用 Day.js + duration 插件
  • React/Vue:牢记 useEffect/生命周期中清理定时器。
  • 持久化:搭配 localStorage 存储起始时间。

如果这个时间段是用来做倒计时(截止未来某个点),逻辑正好反过来(用截止时间减当前时间),需要我展开讲讲吗?😊

使用 performance.now() 显示运行时间段,是Date.now() 更专业的做法。它的核心优势是高精度(微秒级)不受系统时间篡改影响(单调递增),特别适合性能监控、动画帧计算或考试计时等场景。

以下是具体的实现方案和关键区别:

1. 核心实现(原生 JS)

逻辑与 Date.now 完全一致,但起始点记录的是页面加载(或上下文创建)以来的高精度时间

// 1. 记录起始高精度时间戳
const startTime = performance.now();

function formatDuration(ms) {
  const totalSeconds = Math.floor(ms / 1000);
  const hours = String(Math.floor(totalSeconds / 3600)).padStart(2, '0');
  const minutes = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0');
  const seconds = String(totalSeconds % 60).padStart(2, '0');
  // 可选:保留毫秒(精度更高)
  const millis = String(Math.floor(ms % 1000)).padStart(3, '0');
  return `${hours}:${minutes}:${seconds}.${millis}`;
}

// 2. 动态刷新(建议 100ms 更新一次以发挥精度优势)
setInterval(() => {
  const elapsed = performance.now() - startTime;
  console.log(formatDuration(elapsed)); 
  // 输出示例:00:01:23.456
}, 100);

2. 在 React 等框架中实践

注意用 ref 存储起始值,避免组件重渲染导致时间重置:

function Timer() {
  const [ms, setMs] = useState(0);
  const startRef = useRef(performance.now()); // 组件挂载时记录

  useEffect(() => {
    const timer = setInterval(() => {
      setMs(performance.now() - startRef.current);
    }, 100);
    return () => clearInterval(timer);
  }, []);

  return <div>{formatDuration(ms)}</div>;
}

3. ⚠️ 关键注意事项(与 Date.now 对比)

  • 精度优势performance.now() 精度可达微秒级(千分位毫秒),而 Date.now() 是毫秒级。
  • 系统时间免疫:用户修改电脑系统时间,Date.now() 会跳变,但 performance.now() 不受影响,保障计时准确。
  • 页面刷新重置:它记录的是当前页面上下文的启动时间,刷新页面会重置。若需刷新后延续,仍需配合 localStorage 存储起始值(存 Date.now() 更合理,因为 performance 值跨页面无意义)。
  • 定时器延迟setInterval 本身存在 4ms 左右的最小延迟和后台节流,因此显示亚秒级精度虽好看,但不建议用于绝对精准的物理测量;若需极致精准累加,建议用 requestAnimationFrame 替代 setInterval 做 UI 刷新,但计算差值依然用 performance.now()

4. 何时选择 performance.now() 而非 Date.now()

  • performance.now():做性能分析(测量函数执行耗时)、游戏/动画帧率计算本地计时器(担心用户改时间)。
  • Date.now():需要对应具体绝对时间点(如“2026-06-23 12:00”),或需要配合后端时间戳。

如果需要配合 requestAnimationFrame 实现更平滑的毫秒级刷新,或者想了解 performance.mark() 做性能打点,可以告诉我,我再展开讲讲。😊

这里需要先澄清一个关键点:performance.now() 返回值的单位是“毫秒”(ms),而不是微秒(µs)。但它的**精度(分辨率)**达到了微秒级(即小数点后带有3位小数,对应微秒)。

所谓“使用微秒”,核心是指提取并利用好这个高精度的小数部分,主要用于测量极短代码块的执行耗时。具体操作如下:

1. 提取微秒数值(核心计算)

直接相减得到毫秒差值后,乘以 1000 即可转换为微秒:

const start = performance.now();

// 模拟一个极快的操作(比如循环1000次)
for (let i = 0; i < 1000; i++) { /* do something */ }

const end = performance.now();
const diffMs = end - start;          // 例如:0.123 毫秒
const diffUs = diffMs * 1000;        // 转换为 123 微秒(保留高精度)

console.log(`耗时 ${diffUs.toFixed(2)} 微秒`); // 输出:123.45 µs

2. 格式化显示(带微秒的计时器)

如果你想要在界面上显示“时:分:秒.毫秒微秒”,可以这样拆解:

function formatHighPrecision(ms) {
  const totalSeconds = Math.floor(ms / 1000);
  const hours = String(Math.floor(totalSeconds / 3600)).padStart(2, '0');
  const minutes = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0');
  const seconds = String(totalSeconds % 60).padStart(2, '0');
  
  // 提取小数部分:取毫秒(整数)和微秒(小数后3位)
  const millis = Math.floor(ms % 1000);                     // 整数毫秒
  const micros = Math.floor((ms % 1) * 1000);              // 微秒(取小数后3位)

  return `${hours}:${minutes}:${seconds}.${String(millis).padStart(3,'0')}${String(micros).padStart(3,'0')}`;
}
// 若 ms = 3661.123456,则输出 "01:01:01.123456"

3. 微秒使用的“高频刷新”技巧

既然精度达到微秒,若想肉眼看到数字飞快跳动,不能依赖 setInterval(最小间隔约4ms),而要改用 requestAnimationFrame(约16.6ms刷新一次,但显示数值可计算到微秒级):

let startTime = performance.now();

function updateDisplay() {
  const elapsed = performance.now() - startTime;
  // 此时 elapsed 自带微秒小数,直接显示即可
  console.log(elapsed.toFixed(3) + ' ms'); // 每次刷新都带微秒位
  requestAnimationFrame(updateDisplay);
}
updateDisplay();

4. ⚠️ 重大现实限制(务必注意)

浏览器出于安全考虑(防止侧信道攻击),会对 performance.now() 的精度进行降级

  • 普通 HTTP 页面:精度会被限制到 100微秒(0.1ms) 左右。
  • HTTPS + 跨域隔离(Cross-Origin-Opener-Policy 等):才能拿到完整 5微秒(0.005ms) 级别的高精度。

如果你发现怎么乘1000后数值都是整数(如 100.000),说明你的页面环境未开启完整精度

5. 什么时候真要用“微秒”?

  • 性能基准测试:比对 Array.mapfor 循环哪个快(差距常在几十微秒)。
  • 音频/视频帧间隔计算:极短的时间增量累加。
  • 埋点耗时:记录接口从 requestStartresponseStart 的细微差距。

避坑建议:千万不要用微秒累加计算“总运行小时数”(数字会溢出且浮点数精度丢失),微秒只用于测量短时间间隔。若测量超过几秒的时长,直接看毫秒整数部分即可。

如果你的网站是 HTTP 环境,拿不到微秒精度,想了解如何配置 HTTPS + 隔离头来开启完整精度吗?我可以给你 Nginx 配置示例。😊

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐