日期与时间处理:不用库和用 dayjs 的两种思路

前言

前端开发中,日期时间处理很常见:展示"2024-02-18 14:30:00"、对比"是否超过 7 天"、格式化为后端需要的"YYYY-MM-DD HH:mm:ss"。很多人用原生 Date 写得很长,或者直接引入 moment.js(体积大、已不推荐)。

原生 Date APIdayjs(轻量、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,需要 +1padStart(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)
  • HH 24 小时制(00-23),hh 12 小时制(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 的 diffisAfterisBefore 更直观。


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 的 addsubtract 更清晰,避免手动算毫秒。


四、格式化为后端需要的格式

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,你的电子学友。

如果文章对你有帮助,别忘了点赞、收藏、加关注,你的认可是我持续输出的最大动力~

相关推荐
菜鸟小芯2 小时前
【GLM-5 陪练式前端新手入门】第一篇:从 GLM-5 提示到实践,完成前端入门第一步
前端·人工智能
木斯佳2 小时前
前端八股文面经大全:字节跳动交易与广告前端一面(2026-2-10)·面经深度解析
前端
Highcharts.js2 小时前
如何根据派生数据创建钟形曲线图表?highcharts正态分布曲线使用指南:从创建到设置一文搞定
开发语言·javascript·开发文档·正态分布·highcharts·图表类型·钟形图
a1117763 小时前
纸张生成器(html开源)
前端·开源·html
心.c3 小时前
虚拟滚动列表
前端·javascript·vue.js·js
祯民3 小时前
《复合型 AI Agent 开发:从理论到实践》实体书上架
前端
NEXT063 小时前
深拷贝与浅拷贝的区别
前端·javascript·面试
不写八个3 小时前
PixiJS教程(一):快速搭建环境启动项目
前端·pixijs
PieroPc4 小时前
用html+css+js 写一个Docker 教程
javascript·css·docker·html