Javascript教学:前端日期时间等-由Deepseek产生
在前端显示当前日期和时间,主要有以下几种方法,从原生的 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 会被减速。如果不要求绝对精准(比如不涉及计费),默认方案即可;若要求极高精度,可结合 requestAnimationFrame 或 Web 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.map和for循环哪个快(差距常在几十微秒)。 - 音频/视频帧间隔计算:极短的时间增量累加。
- 埋点耗时:记录接口从
requestStart到responseStart的细微差距。
避坑建议:千万不要用微秒累加计算“总运行小时数”(数字会溢出且浮点数精度丢失),微秒只用于测量短时间间隔。若测量超过几秒的时长,直接看毫秒整数部分即可。
如果你的网站是 HTTP 环境,拿不到微秒精度,想了解如何配置 HTTPS + 隔离头来开启完整精度吗?我可以给你 Nginx 配置示例。😊
更多推荐


所有评论(0)