Day.js 教程 - 轻量级的 JavaScript 日期处理库

项目概述

Day.js 是一个轻量级的 JavaScript 日期处理库,提供了与 Moment.js 相似的 API,但体积更小,性能更好。

核心功能

  1. 日期解析:解析各种格式的日期字符串
  2. 日期格式化:将日期格式化为各种字符串格式
  3. 日期操作:添加、减去时间单位
  4. 日期比较:比较两个日期的先后
  5. 国际化:支持多语言
  6. 插件系统:通过插件扩展功能
  7. 轻量级:体积小,压缩后仅 2KB
  8. API 与 Moment.js 兼容:与 Moment.js 的 API 相似,易于迁移
  9. 浏览器支持:支持所有现代浏览器
  10. Node.js 支持:支持 Node.js 环境
  11. TypeScript 支持:良好的 TypeScript 类型定义

安装与设置

基本安装

# 安装 Day.js
npm install dayjs

# 安装特定版本
npm install dayjs@1.11.10

基本设置

// 导入 Day.js
import dayjs from 'dayjs';

// 或者使用 CommonJS 导入
const dayjs = require('dayjs');

// 导入插件
import relativeTime from 'dayjs/plugin/relativeTime';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import 'dayjs/locale/zh-cn'; // 导入中文语言包

// 使用插件
dayjs.extend(relativeTime);
dayjs.extend(localizedFormat);

// 设置默认语言
dayjs.locale('zh-cn');

基本使用

创建日期对象

// 当前日期
dayjs();

// 特定日期
dayjs('2023-01-01');
dayjs('2023-01-01 12:00:00');
dayjs('2023-01-01T12:00:00Z');

// 时间戳
dayjs(1672531200000); // 毫秒时间戳
dayjs.unix(1672531200); // 秒时间戳

// 日期对象
dayjs(new Date());

// 复制日期对象
const date = dayjs();
const copy = dayjs(date);

日期格式化

// 格式化日期
dayjs().format('YYYY-MM-DD'); // 2023-01-01
dayjs().format('YYYY-MM-DD HH:mm:ss'); // 2023-01-01 12:00:00
dayjs().format('YYYY年MM月DD日'); // 2023年01月01日
dayjs().format('HH:mm:ss'); // 12:00:00

// 使用本地化格式(需要 localizedFormat 插件)
dayjs().format('L'); // 01/01/2023
dayjs().format('LL'); // January 1, 2023
dayjs().format('LLL'); // January 1, 2023 12:00 PM
dayjs().format('LLLL'); // Sunday, January 1, 2023 12:00 PM

// 使用相对时间(需要 relativeTime 插件)
dayjs().fromNow(); // 2 hours ago
dayjs().toNow(); // in 2 hours
dayjs('2023-01-01').fromNow(); // 3 months ago

日期操作

// 添加时间
dayjs().add(1, 'day'); // 明天
dayjs().add(1, 'week'); // 下周
dayjs().add(1, 'month'); // 下个月
dayjs().add(1, 'year'); // 明年
dayjs().add(1, 'hour'); // 1小时后
dayjs().add(1, 'minute'); // 1分钟后
dayjs().add(1, 'second'); // 1秒后

// 减去时间
dayjs().subtract(1, 'day'); // 昨天
dayjs().subtract(1, 'week'); // 上周
dayjs().subtract(1, 'month'); // 上个月
dayjs().subtract(1, 'year'); // 去年

// 设置时间
dayjs().set('year', 2023); // 设置年份为 2023
dayjs().set('month', 0); // 设置月份为 1 月(0-11)
dayjs().set('date', 1); // 设置日期为 1 号
dayjs().set('hour', 12); // 设置小时为 12
dayjs().set('minute', 0); // 设置分钟为 0
dayjs().set('second', 0); // 设置秒为 0

日期比较

// 比较两个日期
const date1 = dayjs('2023-01-01');
const date2 = dayjs('2023-01-02');

// 是否在另一个日期之前
date1.isBefore(date2); // true

// 是否在另一个日期之后
date1.isAfter(date2); // false

// 是否与另一个日期相同
date1.isSame(date2); // false

// 是否与另一个日期相同或在其之前
date1.isSameOrBefore(date2); // true

// 是否与另一个日期相同或在其之后
date1.isSameOrAfter(date2); // false

// 比较单位
date1.isBefore(date2, 'year'); // false(年份相同)
date1.isBefore(date2, 'month'); // false(月份相同)
date1.isBefore(date2, 'date'); // true(日期不同)

获取日期部分

// 获取年份
dayjs().year(); // 2023

// 获取月份(0-11)
dayjs().month(); // 0 表示 1 月

// 获取日期(1-31)
dayjs().date(); // 1

// 获取星期(0-6,0 表示星期日)
dayjs().day(); // 0

// 获取小时(0-23)
dayjs().hour(); // 12

// 获取分钟(0-59)
dayjs().minute(); // 0

// 获取秒(0-59)
dayjs().second(); // 0

// 获取毫秒(0-999)
dayjs().millisecond(); // 0

高级特性

插件系统

Day.js 通过插件扩展功能,以下是一些常用插件:

常用插件

# 安装插件(如果使用 npm)
# 注意:Day.js 的插件通常包含在主包中,无需单独安装
// 导入并使用插件
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime'; // 相对时间插件
import localizedFormat from 'dayjs/plugin/localizedFormat'; // 本地化格式插件
import isBetween from 'dayjs/plugin/isBetween'; // 检查日期是否在范围内
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; // 检查日期是否相同或在之前
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'; // 检查日期是否相同或在之后
import customParseFormat from 'dayjs/plugin/customParseFormat'; // 自定义解析格式
import weekOfYear from 'dayjs/plugin/weekOfYear'; // 周数插件
import isoWeek from 'dayjs/plugin/isoWeek'; // ISO 周插件
import quarterOfYear from 'dayjs/plugin/quarterOfYear'; // 季度插件

// 使用插件
dayjs.extend(relativeTime);
dayjs.extend(localizedFormat);
dayjs.extend(isBetween);
dayjs.extend(isSameOrBefore);
dayjs.extend(isSameOrAfter);
dayjs.extend(customParseFormat);
dayjs.extend(weekOfYear);
dayjs.extend(isoWeek);
dayjs.extend(quarterOfYear);

使用相对时间插件

import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';

dayjs.extend(relativeTime);

// 相对时间
dayjs().fromNow(); // 2 hours ago
dayjs().toNow(); // in 2 hours
dayjs('2023-01-01').fromNow(); // 3 months ago
dayjs('2023-12-31').toNow(); // in 9 months

// 两个日期之间的相对时间
const date1 = dayjs('2023-01-01');
const date2 = dayjs('2023-01-02');
date1.from(date2); // 1 day ago
date1.to(date2); // in 1 day

使用自定义解析格式插件

import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';

dayjs.extend(customParseFormat);

// 解析自定义格式的日期字符串
const date = dayjs('2023-01-01 12:00:00', 'YYYY-MM-DD HH:mm:ss');
console.log(date.format('YYYY-MM-DD')); // 2023-01-01

国际化

import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn'; // 导入中文语言包
import 'dayjs/locale/en'; // 导入英文语言包
import 'dayjs/locale/ja'; // 导入日文语言包

// 设置全局语言
dayjs.locale('zh-cn');
console.log(dayjs().format('LLLL')); // 2023年1月1日星期日 12:00

// 临时使用其他语言
console.log(dayjs().locale('en').format('LLLL')); // Sunday, January 1, 2023 12:00 PM
console.log(dayjs().locale('ja').format('LLLL')); // 2023年1月1日日曜日 12:00

日期范围

import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween';

dayjs.extend(isBetween);

// 检查日期是否在范围内
const date = dayjs('2023-01-15');
const start = dayjs('2023-01-01');
const end = dayjs('2023-01-31');

date.isBetween(start, end); // true

// 指定比较单位
date.isBetween(start, end, 'month'); // true

日期克隆

// 克隆日期对象
const date1 = dayjs('2023-01-01');
const date2 = date1.clone();

date2.add(1, 'day');
console.log(date1.format('YYYY-MM-DD')); // 2023-01-01
console.log(date2.format('YYYY-MM-DD')); // 2023-01-02

日期验证

// 验证日期是否有效
dayjs('2023-02-30').isValid(); // false(2月没有30天)
dayjs('2023-01-01').isValid(); // true

// 获取无效日期的原因
dayjs('2023-02-30').invalidReason(); // Invalid Date

实用场景

日期格式化

import dayjs from 'dayjs';

// 格式化当前日期
console.log(dayjs().format('YYYY-MM-DD')); // 2023-01-01
console.log(dayjs().format('YYYY-MM-DD HH:mm:ss')); // 2023-01-01 12:00:00
console.log(dayjs().format('YYYY年MM月DD日')); // 2023年01月01日
console.log(dayjs().format('HH:mm:ss')); // 12:00:00

// 格式化特定日期
const date = dayjs('2023-01-01');
console.log(date.format('YYYY-MM-DD')); // 2023-01-01

相对时间显示

import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/zh-cn';

dayjs.extend(relativeTime);
dayjs.locale('zh-cn');

// 显示相对时间
console.log(dayjs().fromNow()); // 刚刚
console.log(dayjs().subtract(1, 'minute').fromNow()); // 1分钟前
console.log(dayjs().subtract(1, 'hour').fromNow()); // 1小时前
console.log(dayjs().subtract(1, 'day').fromNow()); // 1天前
console.log(dayjs().subtract(1, 'week').fromNow()); // 1周前
console.log(dayjs().subtract(1, 'month').fromNow()); // 1个月前
console.log(dayjs().subtract(1, 'year').fromNow()); // 1年前

// 显示未来相对时间
console.log(dayjs().add(1, 'minute').fromNow()); // 1分钟后
console.log(dayjs().add(1, 'hour').fromNow()); // 1小时后
console.log(dayjs().add(1, 'day').fromNow()); // 1天后

日期计算

import dayjs from 'dayjs';

// 计算两个日期之间的差值
const date1 = dayjs('2023-01-01');
const date2 = dayjs('2023-01-02');

// 计算天数差
console.log(date2.diff(date1, 'day')); // 1

// 计算小时差
console.log(date2.diff(date1, 'hour')); // 24

// 计算分钟差
console.log(date2.diff(date1, 'minute')); // 1440

// 计算秒差
console.log(date2.diff(date1, 'second')); // 86400

// 计算月数差
const date3 = dayjs('2023-02-01');
console.log(date3.diff(date1, 'month')); // 1

// 计算年数差
const date4 = dayjs('2024-01-01');
console.log(date4.diff(date1, 'year')); // 1

日期范围检查

import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween';

dayjs.extend(isBetween);

// 检查日期是否在范围内
function isDateInRange(date, startDate, endDate) {
  return dayjs(date).isBetween(dayjs(startDate), dayjs(endDate), null, '[]');
  // '[]' 表示包含开始和结束日期
}

console.log(isDateInRange('2023-01-15', '2023-01-01', '2023-01-31')); // true
console.log(isDateInRange('2023-02-01', '2023-01-01', '2023-01-31')); // false

日期工具函数

import dayjs from 'dayjs';

// 获取当月第一天
function getFirstDayOfMonth(date) {
  return dayjs(date).startOf('month').format('YYYY-MM-DD');
}

// 获取当月最后一天
function getLastDayOfMonth(date) {
  return dayjs(date).endOf('month').format('YYYY-MM-DD');
}

// 获取当周第一天(星期日)
function getFirstDayOfWeek(date) {
  return dayjs(date).startOf('week').format('YYYY-MM-DD');
}

// 获取当周最后一天(星期六)
function getLastDayOfWeek(date) {
  return dayjs(date).endOf('week').format('YYYY-MM-DD');
}

// 获取今年第一天
function getFirstDayOfYear(date) {
  return dayjs(date).startOf('year').format('YYYY-MM-DD');
}

// 获取今年最后一天
function getLastDayOfYear(date) {
  return dayjs(date).endOf('year').format('YYYY-MM-DD');
}

// 测试
console.log(getFirstDayOfMonth('2023-01-15')); // 2023-01-01
console.log(getLastDayOfMonth('2023-01-15')); // 2023-01-31
console.log(getFirstDayOfWeek('2023-01-15')); // 2023-01-15(假设 2023-01-15 是星期日)
console.log(getLastDayOfWeek('2023-01-15')); // 2023-01-21
console.log(getFirstDayOfYear('2023-01-15')); // 2023-01-01
console.log(getLastDayOfYear('2023-01-15')); // 2023-12-31

最佳实践

  1. 导入必要的插件:只导入需要的插件,减少打包体积
  2. 使用链式调用:Day.js 支持链式调用,使代码更简洁
  3. 注意日期对象的不可变性:Day.js 的方法会返回新的日期对象,不会修改原对象
  4. 使用克隆:当需要基于现有日期进行操作时,使用 clone() 方法
  5. 设置默认语言:根据用户的语言环境设置默认语言
  6. 使用 TypeScript:使用 TypeScript 提供类型安全
  7. 测试:为日期处理逻辑编写测试
  8. 文档:为日期处理逻辑编写文档
  9. 与 Moment.js 迁移:如果从 Moment.js 迁移,注意 API 的细微差异
  10. 性能考虑:对于大量日期处理,注意性能优化

常见问题与解决方案

1. 日期解析失败

问题:解析特定格式的日期字符串失败

解决方案

  • 使用 customParseFormat 插件
  • 确保日期字符串格式正确
  • 检查是否需要指定格式
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';

dayjs.extend(customParseFormat);

// 解析自定义格式的日期字符串
const date = dayjs('01/01/2023', 'MM/DD/YYYY');
console.log(date.format('YYYY-MM-DD')); // 2023-01-01

2. 插件不工作

问题:导入的插件不工作

解决方案

  • 确保正确导入插件
  • 确保使用 extend() 方法注册插件
  • 检查插件名称是否正确
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';

// 正确使用插件
dayjs.extend(relativeTime);
console.log(dayjs().fromNow()); // 现在可以正常工作

3. 国际化不工作

问题:设置语言后,日期格式没有变化

解决方案

  • 确保正确导入语言包
  • 确保使用 locale() 方法设置语言
  • 检查语言包名称是否正确
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';

// 正确设置语言
dayjs.locale('zh-cn');
console.log(dayjs().format('LLLL')); // 现在应该显示中文

4. 日期计算错误

问题:日期计算结果不符合预期

解决方案

  • 检查日期对象是否正确创建
  • 检查使用的时间单位是否正确
  • 检查是否需要使用 clone() 方法
// 错误示例
const date = dayjs('2023-01-01');
date.add(1, 'day'); // 错误:没有赋值
console.log(date.format('YYYY-MM-DD')); // 2023-01-01

// 正确示例
const date = dayjs('2023-01-01');
const newDate = date.add(1, 'day'); // 正确:赋值给新变量
console.log(newDate.format('YYYY-MM-DD')); // 2023-01-02

5. 与 Moment.js 的差异

问题:从 Moment.js 迁移到 Day.js 后,某些代码不工作

解决方案

  • 查看 Day.js 官方文档中的迁移指南
  • 注意 API 的细微差异
  • 检查是否需要导入额外的插件

与其他日期处理库的比较

Day.js vs Moment.js

  • 体积:Day.js 体积小(2KB),Moment.js 体积大(16KB+)
  • API:两者 API 相似,易于迁移
  • 性能:Day.js 性能更好
  • 不可变性:Day.js 返回新的日期对象,Moment.js 修改原对象
  • 插件系统:Day.js 使用插件扩展功能,Moment.js 内置更多功能
  • 语言支持:两者都支持多语言

Day.js vs Date-fns

  • API 风格:Day.js 使用链式调用,Date-fns 使用函数式风格
  • 体积:两者都很小
  • 功能:Date-fns 内置更多功能
  • 不可变性:两者都返回新的日期对象
  • 国际化:两者都支持多语言

Day.js vs 原生 Date 对象

  • API 简洁性:Day.js API 更简洁易读
  • 功能丰富度:Day.js 提供更多功能
  • 浏览器兼容性:Day.js 处理了浏览器兼容性问题
  • 性能:原生 Date 对象性能更好
  • 体积:原生 Date 对象无额外体积

参考资源

  1. 官方文档https://day.js.org/docs/en/installation/installation
  2. GitHub 仓库https://github.com/iamkun/dayjs
  3. 插件列表https://day.js.org/docs/en/plugin/plugin
  4. 语言包列表https://day.js.org/docs/en/i18n/i18n
  5. 与 Moment.js 比较https://day.js.org/docs/en/installation/installation#comparison
  6. TypeScript 支持https://day.js.org/docs/en/installation/typescript
« 上一篇 Axios 教程 - 基于 Promise 的 HTTP 客户端 下一篇 » Moment.js 教程 - JavaScript 日期处理库