Moment.js 教程 - JavaScript 日期处理库
项目概述
Moment.js 是一个传统的 JavaScript 日期处理库,提供了丰富的日期操作功能,但体积较大,现已进入维护模式。
- 项目链接:https://github.com/moment/moment
- 官方网站:https://momentjs.com/
- GitHub Stars:47k+
核心功能
- 日期解析:解析各种格式的日期字符串
- 日期格式化:将日期格式化为各种字符串格式
- 日期操作:添加、减去时间单位
- 日期比较:比较两个日期的先后
- 国际化:支持多语言
- 功能丰富:提供大量日期处理功能
- API 友好:使用链式调用,API 设计友好
- 浏览器支持:支持所有现代浏览器
- Node.js 支持:支持 Node.js 环境
- TypeScript 支持:良好的 TypeScript 类型定义
安装与设置
基本安装
# 安装 Moment.js
npm install moment
# 安装特定版本
npm install moment@2.29.4基本设置
// 导入 Moment.js
import moment from 'moment';
// 或者使用 CommonJS 导入
const moment = require('moment');
// 导入语言包
import 'moment/locale/zh-cn'; // 导入中文语言包
// 设置默认语言
moment.locale('zh-cn');基本使用
创建日期对象
// 当前日期
moment();
// 特定日期
moment('2023-01-01');
moment('2023-01-01 12:00:00');
moment('2023-01-01T12:00:00Z');
// 时间戳
moment(1672531200000); // 毫秒时间戳
moment.unix(1672531200); // 秒时间戳
// 日期对象
moment(new Date());
// 复制日期对象
const date = moment();
const copy = moment(date);日期格式化
// 格式化日期
moment().format('YYYY-MM-DD'); // 2023-01-01
moment().format('YYYY-MM-DD HH:mm:ss'); // 2023-01-01 12:00:00
moment().format('YYYY年MM月DD日'); // 2023年01月01日
moment().format('HH:mm:ss'); // 12:00:00
// 使用本地化格式
moment().format('L'); // 01/01/2023
moment().format('LL'); // January 1, 2023
moment().format('LLL'); // January 1, 2023 12:00 PM
moment().format('LLLL'); // Sunday, January 1, 2023 12:00 PM
// 使用相对时间
moment().fromNow(); // 2 hours ago
moment().toNow(); // in 2 hours
moment('2023-01-01').fromNow(); // 3 months ago日期操作
// 添加时间
moment().add(1, 'day'); // 明天
moment().add(1, 'week'); // 下周
moment().add(1, 'month'); // 下个月
moment().add(1, 'year'); // 明年
moment().add(1, 'hour'); // 1小时后
moment().add(1, 'minute'); // 1分钟后
moment().add(1, 'second'); // 1秒后
// 减去时间
moment().subtract(1, 'day'); // 昨天
moment().subtract(1, 'week'); // 上周
moment().subtract(1, 'month'); // 上个月
moment().subtract(1, 'year'); // 去年
// 设置时间
moment().year(2023); // 设置年份为 2023
moment().month(0); // 设置月份为 1 月(0-11)
moment().date(1); // 设置日期为 1 号
moment().hour(12); // 设置小时为 12
moment().minute(0); // 设置分钟为 0
moment().second(0); // 设置秒为 0日期比较
// 比较两个日期
const date1 = moment('2023-01-01');
const date2 = moment('2023-01-02');
// 是否在另一个日期之前
date1.isBefore(date2); // true
// 是否在另一个日期之后
date1.isAfter(date2); // false
// 是否与另一个日期相同
date1.isSame(date2); // false
// 比较单位
date1.isBefore(date2, 'year'); // false(年份相同)
date1.isBefore(date2, 'month'); // false(月份相同)
date1.isBefore(date2, 'date'); // true(日期不同)获取日期部分
// 获取年份
moment().year(); // 2023
// 获取月份(0-11)
moment().month(); // 0 表示 1 月
// 获取日期(1-31)
moment().date(); // 1
// 获取星期(0-6,0 表示星期日)
moment().day(); // 0
// 获取小时(0-23)
moment().hour(); // 12
// 获取分钟(0-59)
moment().minute(); // 0
// 获取秒(0-59)
moment().second(); // 0
// 获取毫秒(0-999)
moment().millisecond(); // 0高级特性
国际化
import moment from 'moment';
import 'moment/locale/zh-cn'; // 导入中文语言包
import 'moment/locale/en'; // 导入英文语言包
import 'moment/locale/ja'; // 导入日文语言包
// 设置全局语言
moment.locale('zh-cn');
console.log(moment().format('LLLL')); // 2023年1月1日星期日 12:00
// 临时使用其他语言
console.log(moment().locale('en').format('LLLL')); // Sunday, January 1, 2023 12:00 PM
console.log(moment().locale('ja').format('LLLL')); // 2023年1月1日日曜日 12:00日期范围
// 检查日期是否在范围内
const date = moment('2023-01-15');
const start = moment('2023-01-01');
const end = moment('2023-01-31');
const isBetween = date.isAfter(start) && date.isBefore(end);
console.log(isBetween); // true
// 包含边界
const isBetweenInclusive = date.isSameOrAfter(start) && date.isSameOrBefore(end);
console.log(isBetweenInclusive); // true日期克隆
// 克隆日期对象
const date1 = moment('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日期验证
// 验证日期是否有效
moment('2023-02-30').isValid(); // false(2月没有30天)
moment('2023-01-01').isValid(); // true
// 获取无效日期的原因
moment('2023-02-30').invalidAt(); // 2(表示日期部分无效)实用场景
日期格式化
import moment from 'moment';
// 格式化当前日期
console.log(moment().format('YYYY-MM-DD')); // 2023-01-01
console.log(moment().format('YYYY-MM-DD HH:mm:ss')); // 2023-01-01 12:00:00
console.log(moment().format('YYYY年MM月DD日')); // 2023年01月01日
console.log(moment().format('HH:mm:ss')); // 12:00:00
// 格式化特定日期
const date = moment('2023-01-01');
console.log(date.format('YYYY-MM-DD')); // 2023-01-01相对时间显示
import moment from 'moment';
import 'moment/locale/zh-cn';
// 设置语言
moment.locale('zh-cn');
// 显示相对时间
console.log(moment().fromNow()); // 刚刚
console.log(moment().subtract(1, 'minute').fromNow()); // 1分钟前
console.log(moment().subtract(1, 'hour').fromNow()); // 1小时前
console.log(moment().subtract(1, 'day').fromNow()); // 1天前
console.log(moment().subtract(1, 'week').fromNow()); // 1周前
console.log(moment().subtract(1, 'month').fromNow()); // 1个月前
console.log(moment().subtract(1, 'year').fromNow()); // 1年前
// 显示未来相对时间
console.log(moment().add(1, 'minute').fromNow()); // 1分钟后
console.log(moment().add(1, 'hour').fromNow()); // 1小时后
console.log(moment().add(1, 'day').fromNow()); // 1天后日期计算
import moment from 'moment';
// 计算两个日期之间的差值
const date1 = moment('2023-01-01');
const date2 = moment('2023-01-02');
// 计算天数差
console.log(date2.diff(date1, 'days')); // 1
// 计算小时差
console.log(date2.diff(date1, 'hours')); // 24
// 计算分钟差
console.log(date2.diff(date1, 'minutes')); // 1440
// 计算秒差
console.log(date2.diff(date1, 'seconds')); // 86400
// 计算月数差
const date3 = moment('2023-02-01');
console.log(date3.diff(date1, 'months')); // 1
// 计算年数差
const date4 = moment('2024-01-01');
console.log(date4.diff(date1, 'years')); // 1日期范围检查
import moment from 'moment';
// 检查日期是否在范围内
function isDateInRange(date, startDate, endDate) {
const momentDate = moment(date);
const momentStart = moment(startDate);
const momentEnd = moment(endDate);
return momentDate.isSameOrAfter(momentStart) && momentDate.isSameOrBefore(momentEnd);
}
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 moment from 'moment';
// 获取当月第一天
function getFirstDayOfMonth(date) {
return moment(date).startOf('month').format('YYYY-MM-DD');
}
// 获取当月最后一天
function getLastDayOfMonth(date) {
return moment(date).endOf('month').format('YYYY-MM-DD');
}
// 获取当周第一天(星期日)
function getFirstDayOfWeek(date) {
return moment(date).startOf('week').format('YYYY-MM-DD');
}
// 获取当周最后一天(星期六)
function getLastDayOfWeek(date) {
return moment(date).endOf('week').format('YYYY-MM-DD');
}
// 获取今年第一天
function getFirstDayOfYear(date) {
return moment(date).startOf('year').format('YYYY-MM-DD');
}
// 获取今年最后一天
function getLastDayOfYear(date) {
return moment(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最佳实践
- 注意体积:Moment.js 体积较大,考虑使用 Day.js 等轻量级替代方案
- 使用链式调用:Moment.js 支持链式调用,使代码更简洁
- 注意日期对象的可变性:Moment.js 的方法会修改原对象,注意使用 clone() 方法
- 设置默认语言:根据用户的语言环境设置默认语言
- 使用 TypeScript:使用 TypeScript 提供类型安全
- 测试:为日期处理逻辑编写测试
- 文档:为日期处理逻辑编写文档
- 考虑迁移:考虑迁移到 Day.js 等轻量级替代方案
常见问题与解决方案
1. 体积过大
问题:Moment.js 体积较大,影响打包体积
解决方案:
- 考虑使用 Day.js 等轻量级替代方案
- 使用 webpack 的 Tree Shaking(但 Moment.js 可能不支持)
- 只导入需要的语言包
2. 日期对象的可变性
问题:Moment.js 的方法会修改原对象
解决方案:
- 使用 clone() 方法创建副本
- 注意方法调用顺序
// 错误示例
const date = moment('2023-01-01');
date.add(1, 'day'); // 修改了原对象
console.log(date.format('YYYY-MM-DD')); // 2023-01-02
// 正确示例
const date = moment('2023-01-01');
const newDate = date.clone().add(1, 'day'); // 使用 clone()
console.log(date.format('YYYY-MM-DD')); // 2023-01-01
console.log(newDate.format('YYYY-MM-DD')); // 2023-01-023. 国际化不工作
问题:设置语言后,日期格式没有变化
解决方案:
- 确保正确导入语言包
- 确保使用 locale() 方法设置语言
- 检查语言包名称是否正确
import moment from 'moment';
import 'moment/locale/zh-cn';
// 正确设置语言
moment.locale('zh-cn');
console.log(moment().format('LLLL')); // 现在应该显示中文4. 日期计算错误
问题:日期计算结果不符合预期
解决方案:
- 检查日期对象是否正确创建
- 检查使用的时间单位是否正确
- 注意 Moment.js 的可变性,使用 clone() 方法
与其他日期处理库的比较
Moment.js vs Day.js
- 体积:Moment.js 体积大(16KB+),Day.js 体积小(2KB)
- API:两者 API 相似,易于迁移
- 性能:Day.js 性能更好
- 不可变性:Moment.js 修改原对象,Day.js 返回新的日期对象
- 插件系统:Day.js 使用插件扩展功能,Moment.js 内置更多功能
- 维护状态:Moment.js 已进入维护模式,Day.js 仍在积极开发
Moment.js vs Date-fns
- API 风格:Moment.js 使用链式调用,Date-fns 使用函数式风格
- 体积:Date-fns 体积小,支持按需导入
- 功能:两者功能相似
- 不可变性:Moment.js 修改原对象,Date-fns 返回新的日期对象
- 维护状态:Date-fns 仍在积极开发
Moment.js vs 原生 Date 对象
- API 简洁性:Moment.js API 更简洁易读
- 功能丰富度:Moment.js 提供更多功能
- 浏览器兼容性:Moment.js 处理了浏览器兼容性问题
- 性能:原生 Date 对象性能更好
- 体积:原生 Date 对象无额外体积
参考资源
- 官方文档:https://momentjs.com/docs/
- GitHub 仓库:https://github.com/moment/moment
- 语言包列表:https://momentjs.com/docs/#/i18n/
- 与 Day.js 比较:https://day.js.org/docs/en/installation/installation#comparison
- TypeScript 支持:https://momentjs.com/docs/#/use-it/typescript/