前言
前端开发中,日期时间处理很常见:展示"2024-02-18 14:30:00"、对比"是否超过 7 天"、格式化为后端需要的"YYYY-MM-DD HH:mm:ss"。很多人用原生 Date 写得很长,或者直接引入 moment.js(体积大、已不推荐)。
用原生 Date API 或 dayjs(轻量、API 简洁)都能完成。本文通过常见场景,说明什么时候用原生、什么时候用 dayjs、容易踩的坑,只讲 80% 会用到的部分。
适合读者:
- 会写 JS,但对日期格式化、时间对比写法不清晰
- 刚学 JS,希望一开始就掌握日期处理
- 有经验的前端,想统一团队的时间处理方式
一、先搞清楚:原生 Date vs dayjs 的区别
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 原生 Date | 无需安装、浏览器原生支持 | API 不够直观、格式化要手写、月份从 0 开始 | 简单场景、不想引入依赖 |
| dayjs | API 简洁、链式调用、体积小(2KB)、格式化方便 | 需要安装、部分功能需插件 | 格式化需求多、需要相对时间、团队统一规范 |
javascript
// 原生 Date:格式化要手写,月份要 +1
const date = new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始
const day = String(date.getDate()).padStart(2, '0');
const formatted = `${year}-${month}-${day}`; // '2024-02-18'
// dayjs:一行搞定,可读性强
const formatted2 = dayjs().format('YYYY-MM-DD'); // '2024-02-18'
记住一点:简单格式化用原生也能写,但格式化多、需要相对时间、团队统一规范时,用 dayjs 更省事。
二、展示时间:格式化为用户看到的格式
1. 原生方式:手写格式化函数
场景: 把 Date 对象或时间戳格式化成 "2024-02-18 14:30:00"。
javascript
// 方案一:手写格式化函数(适合简单场景)
function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
const d = date instanceof Date ? date : new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0'); // 注意:月份从 0 开始
const day = String(d.getDate()).padStart(2, '0');
const hours = String(d.getHours()).padStart(2, '0');
const minutes = String(d.getMinutes()).padStart(2, '0');
const seconds = String(d.getSeconds()).padStart(2, '0');
return format
.replace('YYYY', year)
.replace('MM', month)
.replace('DD', day)
.replace('HH', hours)
.replace('mm', minutes)
.replace('ss', seconds);
}
const now = new Date();
console.log(formatDate(now)); // '2024-02-18 14:30:00'
console.log(formatDate(now, 'YYYY-MM-DD')); // '2024-02-18'
注意: getMonth() 返回 0-11,需要 +1;padStart(2, '0') 用于补零。
2. dayjs 方式:一行格式化
场景: 同样的格式化需求,用 dayjs 更简洁。
javascript
import dayjs from 'dayjs';
const now = dayjs();
console.log(now.format('YYYY-MM-DD HH:mm:ss')); // '2024-02-18 14:30:00'
console.log(now.format('YYYY-MM-DD')); // '2024-02-18'
console.log(now.format('YYYY年MM月DD日')); // '2024年02月18日'
// 时间戳转格式化
const timestamp = 1708248600000;
console.log(dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')); // '2024-02-18 14:30:00'
// 字符串转格式化
console.log(dayjs('2024-02-18').format('YYYY-MM-DD')); // '2024-02-18'
常用格式符:
YYYY四位年份,YY两位年份MM两位月份(01-12),M一位月份(1-12)DD两位日期(01-31),D一位日期(1-31)HH24 小时制(00-23),hh12 小时制(01-12)mm分钟(00-59),ss秒(00-59)
3. 相对时间展示:几秒前、几小时前
场景: 评论时间显示"2 分钟前""3 小时前"。
javascript
// 原生方式:手写计算(麻烦且容易出错)
function getRelativeTime(timestamp) {
const now = Date.now();
const diff = now - timestamp;
const seconds = Math.floor(diff / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) return `${days}天前`;
if (hours > 0) return `${hours}小时前`;
if (minutes > 0) return `${minutes}分钟前`;
return '刚刚';
}
// dayjs 方式:需要 relativeTime 插件
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/zh-cn'; // 中文
dayjs.extend(relativeTime);
dayjs.locale('zh-cn');
const time = dayjs('2024-02-18 14:00:00');
console.log(time.fromNow()); // '2小时前'
console.log(dayjs().fromNow()); // '几秒前'
relativeTime的Api:
| 方法 | 作用 | 示例 |
|---|---|---|
.fromNow() |
相对当前时间的描述 | dayjs('1990-01-01').fromNow() → "35 years ago" |
.fromNow(true) |
同上,但去掉 "ago" / "in" | dayjs('1990-01-01').fromNow(true) → "35 years" |
.toNow() |
从现在到该时间的描述 | 与 fromNow 类似,语义相反 |
.to(其他日期) |
相对某个日期的描述 | dayjs('2025-03-01').to(dayjs('2025-02-20')) |
.from(其他日期) |
从某个日期到该时间的描述 | 同上,方向相反 |
推荐: 相对时间用 dayjs + relativeTime 插件,原生手写容易出错。
三、对比时间:判断大小、计算差值
4. 原生方式:时间戳对比
场景: 判断订单是否超过 7 天、活动是否已结束。
javascript
// 判断是否超过 7 天
function isOver7Days(timestamp) {
const now = Date.now();
const sevenDays = 7 * 24 * 60 * 60 * 1000; // 7 天的毫秒数
return now - timestamp > sevenDays;
}
const orderTime = new Date('2024-02-10').getTime();
console.log(isOver7Days(orderTime)); // true(假设现在是 2024-02-18)
// 判断活动是否已结束
function isActivityEnded(endTime) {
return Date.now() > new Date(endTime).getTime();
}
console.log(isActivityEnded('2024-02-20 23:59:59')); // false
注意: 时间对比统一用时间戳(getTime() 或 Date.now()),避免直接用 Date 对象比较。
5. dayjs 方式:链式调用更清晰
场景: 同样的对比需求,用 dayjs 更直观。
javascript
import dayjs from 'dayjs';
// 判断是否超过 7 天
const orderTime = dayjs('2024-02-10');
const isOver7Days = dayjs().diff(orderTime, 'day') > 7;
console.log(isOver7Days); // true
// 计算时间差(天数、小时数)
const start = dayjs('2024-02-10 10:00:00');
const end = dayjs('2024-02-18 14:30:00');
console.log(end.diff(start, 'day')); // 8(天数差)
console.log(end.diff(start, 'hour')); // 196(小时数差)
console.log(end.diff(start, 'minute')); // 11790(分钟数差)
// 判断活动是否已结束
const activityEnd = dayjs('2024-02-20 23:59:59');
const isEnded = dayjs().isAfter(activityEnd);
console.log(isEnded); // false
// 其他常用对比方法
dayjs().isBefore(activityEnd); // 是否在之前
dayjs().isSame(activityEnd, 'day'); // 是否同一天
dayjs().isBetween(start, end); // 是否在区间内(需要 isBetween 插件)
推荐: 需要计算差值、判断前后关系时,dayjs 的 diff、isAfter、isBefore 更直观。
6. 计算未来/过去时间:加几天、减几小时
场景: 计算"7 天后""3 小时前"的时间。
javascript
// 原生方式:手动计算毫秒数
const now = Date.now();
const sevenDaysLater = new Date(now + 7 * 24 * 60 * 60 * 1000);
const threeHoursAgo = new Date(now - 3 * 60 * 60 * 1000);
// dayjs 方式:链式调用,可读性强
import dayjs from 'dayjs';
const sevenDaysLater = dayjs().add(7, 'day');
const threeHoursAgo = dayjs().subtract(3, 'hour');
const nextMonth = dayjs().add(1, 'month');
console.log(sevenDaysLater.format('YYYY-MM-DD')); // '2024-02-25'
console.log(threeHoursAgo.format('YYYY-MM-DD HH:mm:ss')); // '2024-02-18 11:30:00'
推荐: 需要加减时间时,dayjs 的 add、subtract 更清晰,避免手动算毫秒。
四、格式化为后端需要的格式
7. 后端常见格式:ISO 8601、时间戳
场景: 提交表单时,日期要转成后端需要的格式。
javascript
// 原生方式
const date = new Date('2024-02-18 14:30:00');
// ISO 8601 格式(后端常用)
const isoString = date.toISOString(); // '2024-02-18T06:30:00.000Z'(UTC 时间)
// 时间戳(毫秒)
const timestamp = date.getTime(); // 1708248600000
// 时间戳(秒,部分后端需要)
const timestampSeconds = Math.floor(date.getTime() / 1000); // 1708248600
// dayjs 方式
import dayjs from 'dayjs';
const date = dayjs('2024-02-18 14:30:00');
// ISO 8601 格式
const isoString = date.toISOString(); // '2024-02-18T06:30:00.000Z'
// 时间戳(毫秒)
const timestamp = date.valueOf(); // 或 date.unix() * 1000
// 时间戳(秒)
const timestampSeconds = date.unix(); // 1708248600
// 自定义格式(后端要求 'YYYY-MM-DD HH:mm:ss')
const customFormat = date.format('YYYY-MM-DD HH:mm:ss'); // '2024-02-18 14:30:00'
注意: toISOString() 返回 UTC 时间,如果后端需要本地时间,用 format() 自定义格式。
ps·UTC时间不属于任何一个国家,它是全球通用的国际时间标准,由国际组织协调维护
8. 表单日期选择器:处理初始值和提交值
场景: 表单里日期选择器,初始值从后端来,提交时要格式化。
javascript
// 场景:编辑表单,后端返回 '2024-02-18',要显示在日期选择器
// 日期选择器通常需要 Date 对象或 'YYYY-MM-DD' 字符串
// 原生方式
const backendDate = '2024-02-18';
const dateForPicker = new Date(backendDate); // 转成 Date 对象
// 提交时,转回后端需要的格式
const submitValue = dateForPicker.toISOString().split('T')[0]; // '2024-02-18'
// dayjs 方式(更简洁)
import dayjs from 'dayjs';
const backendDate = '2024-02-18';
const dateForPicker = dayjs(backendDate).toDate(); // 转成 Date 对象(如果选择器需要)
// 提交时
const submitValue = dayjs(dateForPicker).format('YYYY-MM-DD'); // '2024-02-18'
// 如果后端需要时间戳
const submitTimestamp = dayjs(dateForPicker).unix(); // 1708248600(秒)
推荐: 表单日期处理用 dayjs,格式转换更简单。
五、容易踩的坑
1. 月份从 0 开始:getMonth() 返回 0-11
javascript
const date = new Date(2024, 1, 18); // 注意:1 表示 2 月
console.log(date.getMonth()); // 1(不是 2)
console.log(date.getMonth() + 1); // 2(正确)
// dayjs 没有这个问题
const date2 = dayjs('2024-02-18');
console.log(date2.month() + 1); // 2(month() 也是 0-11,但 format 会自动处理)
2. 时区问题:toISOString() 返回 UTC 时间
javascript
const date = new Date('2024-02-18 14:30:00');
console.log(date.toISOString()); // '2024-02-18T06:30:00.000Z'(UTC,比本地时间少 8 小时)
// 如果后端需要本地时间格式,用 format
const localFormat = dayjs(date).format('YYYY-MM-DD HH:mm:ss'); // '2024-02-18 14:30:00'
注意: 后端要求本地时间时,不要用 toISOString(),用 format() 自定义格式。
3. 字符串解析:不同格式可能解析失败
javascript
// 原生 Date 解析字符串,格式不统一可能失败
new Date('2024-02-18'); // ✅ 可以
new Date('2024/02/18'); // ✅ 可以
new Date('18-02-2024'); // ❌ 可能解析失败(不同浏览器结果不同)
// dayjs 解析更宽松,但也要注意格式
dayjs('2024-02-18'); // ✅
dayjs('2024/02/18'); // ✅
dayjs('18-02-2024'); // ⚠️ 可能解析错误
// 推荐:统一格式,或明确指定格式(需要 customParseFormat 插件)
import customParseFormat from 'dayjs/plugin/customParseFormat';
dayjs.extend(customParseFormat);
dayjs('18-02-2024', 'DD-MM-YYYY'); // ✅ 明确指定格式
4. 时间戳单位:毫秒 vs 秒
javascript
// JavaScript Date 用毫秒
const timestampMs = Date.now(); // 1708248600000
// 部分后端接口需要秒
const timestampSeconds = Math.floor(Date.now() / 1000); // 1708248600
// dayjs 区分清晰
dayjs().valueOf(); // 毫秒
dayjs().unix(); // 秒
注意: 提交时间戳前确认后端要的是毫秒还是秒。
5. 日期比较:直接用 Date 对象可能不准确
javascript
// ❌ 不推荐:直接用 Date 对象比较(比较的是对象引用)
const d1 = new Date('2024-02-18');
const d2 = new Date('2024-02-18');
console.log(d1 === d2); // false(对象引用不同)
// ✅ 推荐:用时间戳比较
console.log(d1.getTime() === d2.getTime()); // true
// ✅ dayjs 方式
console.log(dayjs(d1).isSame(dayjs(d2))); // true
六、实战推荐写法模板
格式化当前时间(原生):
javascript
function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
const d = date instanceof Date ? date : new Date(date);
const pad = (n) => String(n).padStart(2, '0');
return format
.replace('YYYY', d.getFullYear())
.replace('MM', pad(d.getMonth() + 1))
.replace('DD', pad(d.getDate()))
.replace('HH', pad(d.getHours()))
.replace('mm', pad(d.getMinutes()))
.replace('ss', pad(d.getSeconds()));
}
格式化当前时间(dayjs):
javascript
import dayjs from 'dayjs';
const formatDate = (date, format = 'YYYY-MM-DD HH:mm:ss') =>
dayjs(date).format(format);
判断是否超过 N 天(原生):
javascript
function isOverNDays(timestamp, days) {
return Date.now() - timestamp > days * 24 * 60 * 60 * 1000;
}
判断是否超过 N 天(dayjs):
javascript
import dayjs from 'dayjs';
const isOverNDays = (timestamp, days) =>
dayjs().diff(dayjs(timestamp), 'day') > days;
计算时间差(天数):
javascript
// 原生
const diffDays = (start, end) =>
Math.floor((new Date(end).getTime() - new Date(start).getTime()) / (24 * 60 * 60 * 1000));
// dayjs
const diffDays = (start, end) =>
dayjs(end).diff(dayjs(start), 'day');
表单日期处理(dayjs 推荐):
javascript
import dayjs from 'dayjs';
// 后端返回的日期 → 表单初始值
const initValue = dayjs(backendDate).format('YYYY-MM-DD');
// 表单提交 → 后端需要的格式
const submitValue = dayjs(formDate).format('YYYY-MM-DD'); // 或 .unix() 转时间戳
相对时间展示(dayjs + 插件):
javascript
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/zh-cn';
dayjs.extend(relativeTime);
dayjs.locale('zh-cn');
const getRelativeTime = (timestamp) => dayjs(timestamp).fromNow();
七、小结
| 场景 | 原生方式 | dayjs 方式 | 推荐 |
|---|---|---|---|
| 简单格式化 | 手写 formatDate 函数 |
dayjs().format('YYYY-MM-DD') |
dayjs(更简洁) |
| 相对时间 | 手写计算逻辑 | dayjs().fromNow() + 插件 |
dayjs(原生太麻烦) |
| 时间对比 | getTime() 比较时间戳 |
dayjs().isAfter() / diff() |
dayjs(API 更直观) |
| 时间计算 | 手动算毫秒数 | dayjs().add(7, 'day') |
dayjs(可读性强) |
| 后端格式 | toISOString() / getTime() |
dayjs().toISOString() / unix() |
都可以,dayjs 更统一 |
| 表单日期 | new Date() + toISOString() |
dayjs().format() / toDate() |
dayjs(格式转换方便) |
选择建议:
- 简单项目、不想引入依赖 :用原生
Date,手写格式化函数 - 格式化需求多、需要相对时间、团队统一规范:用 dayjs(体积小、API 简洁)
记住:原生 Date 的月份从 0 开始,格式化要手写;dayjs 格式化方便,但需要安装。根据项目需求选择,不要过度设计。
特别提醒:
- 时间对比统一用时间戳或 dayjs 的
isAfter/isBefore,不要直接比较 Date 对象 toISOString()返回 UTC 时间,后端需要本地时间时用format()自定义格式- 时间戳注意单位(毫秒 vs 秒),提交前确认后端要求
- 字符串解析注意格式,不确定时用 dayjs 的
customParseFormat插件明确指定格式
以上就是本次的学习分享,欢迎大家在评论区讨论指正,与大家共勉。
我是 Eugene,你的电子学友。
如果文章对你有帮助,别忘了点赞、收藏、加关注,你的认可是我持续输出的最大动力~