|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
JavaScript中的日期处理是Web开发中常见但又容易出错的任务。无论是显示文章发布时间、处理用户输入的日期,还是进行时间相关的计算,开发者都需要掌握JavaScript的日期处理能力。然而,JavaScript的原生Date对象有时使用起来不够直观,特别是在格式化和时区处理方面。本文将从基础Date对象开始,逐步介绍高级的日期格式化技巧,帮助开发者解决实际开发中的日期显示问题。
JavaScript Date对象基础
创建Date对象
在JavaScript中,可以通过多种方式创建Date对象:
- // 创建当前日期和时间的Date对象
- const now = new Date();
- // 创建指定日期的Date对象(月份从0开始,0代表一月)
- const specificDate = new Date(2023, 5, 15); // 2023年6月15日
- // 创建指定日期和时间的Date对象
- const specificDateTime = new Date(2023, 5, 15, 14, 30, 0); // 2023年6月15日 14:30:00
- // 从日期字符串创建Date对象
- const dateFromString = new Date('2023-06-15T14:30:00');
- // 从时间戳创建Date对象
- const dateFromTimestamp = new Date(1686805800000); // 对应2023-06-15T14:30:00Z
复制代码
需要注意的是,JavaScript中的月份是从0开始的(0代表一月,11代表十二月),这是一个常见的错误源。此外,当从字符串创建Date对象时,最好使用ISO 8601格式(YYYY-MM-DDTHH:mm:ss.sssZ),因为这种格式在所有现代浏览器中都能被正确解析。
Date对象的主要方法
Date对象提供了许多方法来获取和设置日期和时间的各个部分:
- const now = new Date();
- // 获取方法
- console.log(now.getFullYear()); // 四位数年份
- console.log(now.getMonth()); // 月份(0-11)
- console.log(now.getDate()); // 月份中的日期(1-31)
- console.log(now.getDay()); // 星期几(0-6,0代表周日)
- console.log(now.getHours()); // 小时(0-23)
- console.log(now.getMinutes()); // 分钟(0-59)
- console.log(now.getSeconds()); // 秒(0-59)
- console.log(now.getMilliseconds()); // 毫秒(0-999)
- console.log(now.getTime()); // 自1970年1月1日以来的毫秒数(时间戳)
- // 设置方法
- now.setFullYear(2024);
- now.setMonth(6); // 设置为7月
- now.setDate(20);
- now.setHours(15);
- now.setMinutes(45);
- now.setSeconds(30);
- now.setMilliseconds(500);
- now.setTime(1687200000000); // 使用时间戳设置
复制代码
获取日期和时间组件
在实际开发中,我们经常需要获取日期和时间的各个组件,并进行格式化或计算:
- const now = new Date();
- // 获取格式化的日期组件
- const year = now.getFullYear();
- const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份补零
- const day = String(now.getDate()).padStart(2, '0'); // 日期补零
- // 获取格式化的时间组件
- const hours = String(now.getHours()).padStart(2, '0'); // 小时补零
- const minutes = String(now.getMinutes()).padStart(2, '0'); // 分钟补零
- const seconds = String(now.getSeconds()).padStart(2, '0'); // 秒补零
- // 组合成日期时间字符串
- const formattedDateTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
- console.log(formattedDateTime); // 例如:2023-06-15 14:30:00
复制代码
日期格式化的基础方法
使用Date对象内置方法
JavaScript的Date对象提供了一些内置方法用于格式化日期,但这些方法的输出格式因浏览器和地区而异,通常不建议在生产环境中直接使用:
- const now = new Date();
- // toString() - 返回完整的日期字符串
- console.log(now.toString()); // 例如:Thu Jun 15 2023 14:30:00 GMT+0800 (中国标准时间)
- // toDateString() - 只返回日期部分
- console.log(now.toDateString()); // 例如:Thu Jun 15 2023
- // toTimeString() - 只返回时间部分
- console.log(now.toTimeString()); // 例如:14:30:00 GMT+0800 (中国标准时间)
- // toLocaleString() - 根据本地环境格式化日期时间
- console.log(now.toLocaleString()); // 例如:2023/6/15 14:30:00
- // toLocaleDateString() - 根据本地环境格式化日期
- console.log(now.toLocaleDateString()); // 例如:2023/6/15
- // toLocaleTimeString() - 根据本地环境格式化时间
- console.log(now.toLocaleTimeString()); // 例如:14:30:00
- // toISOString() - 返回ISO 8601格式的日期字符串
- console.log(now.toISOString()); // 例如:2023-06-15T06:30:00.000Z
复制代码
手动格式化日期字符串
由于内置方法的局限性,开发者经常需要手动格式化日期字符串:
- function formatDate(date, format) {
- const year = date.getFullYear();
- const month = date.getMonth() + 1;
- const day = date.getDate();
- const hours = date.getHours();
- const minutes = date.getMinutes();
- const seconds = date.getSeconds();
-
- // 替换格式字符串中的占位符
- return format
- .replace('YYYY', year)
- .replace('YY', String(year).slice(-2))
- .replace('MM', String(month).padStart(2, '0'))
- .replace('M', month)
- .replace('DD', String(day).padStart(2, '0'))
- .replace('D', day)
- .replace('HH', String(hours).padStart(2, '0'))
- .replace('H', hours)
- .replace('mm', String(minutes).padStart(2, '0'))
- .replace('m', minutes)
- .replace('SS', String(seconds).padStart(2, '0'))
- .replace('S', seconds);
- }
- const now = new Date();
- console.log(formatDate(now, 'YYYY-MM-DD HH:mm:ss')); // 例如:2023-06-15 14:30:00
- console.log(formatDate(now, 'YY/M/D H:m:S')); // 例如:23/6/15 14:30:0
复制代码
这种方法提供了更多的灵活性,但需要开发者自己处理各种格式化需求,包括本地化、时区等复杂问题。
高级日期格式化技巧
使用Intl.DateTimeFormat API
现代JavaScript提供了Intl.DateTimeFormat API,这是一个强大的国际化日期格式化工具:
- const now = new Date();
- // 基本用法
- const formatter = new Intl.DateTimeFormat('zh-CN');
- console.log(formatter.format(now)); // 例如:2023/6/15
- // 指定格式选项
- const options = {
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- hour12: false,
- timeZone: 'Asia/Shanghai'
- };
- const chineseFormatter = new Intl.DateTimeFormat('zh-CN', options);
- console.log(chineseFormatter.format(now)); // 例如:2023年6月15日 14:30:00
- // 美国英语格式
- const usFormatter = new Intl.DateTimeFormat('en-US', options);
- console.log(usFormatter.format(now)); // 例如:June 15, 2023, 14:30:00
- // 德国德语格式
- const germanFormatter = new Intl.DateTimeFormat('de-DE', options);
- console.log(germanFormatter.format(now)); // 例如:15. Juni 2023, 14:30:00
- // 使用formatToParts方法获取更细粒度的控制
- const partsFormatter = new Intl.DateTimeFormat('zh-CN', {
- year: 'numeric',
- month: 'long',
- day: 'numeric'
- });
- const parts = partsFormatter.formatToParts(now);
- console.log(parts);
- // 输出:
- // [
- // { type: 'year', value: '2023' },
- // { type: 'literal', value: '年' },
- // { type: 'month', value: '6' },
- // { type: 'literal', value: '月' },
- // { type: 'day', value: '15' },
- // { type: 'literal', value: '日' }
- // ]
复制代码
Intl.DateTimeFormat API提供了丰富的选项,可以满足大多数国际化日期格式化需求,而且性能通常优于手动格式化。
使用第三方库
虽然JavaScript原生API提供了基本的日期处理功能,但在复杂项目中,使用专门的日期库可以大大简化开发工作。以下是几个流行的JavaScript日期库:
Moment.js曾经是最流行的JavaScript日期库,但现在已进入维护模式,不推荐在新项目中使用:
- // 需要先引入moment.js库
- // <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
- const now = moment();
- // 格式化日期
- console.log(now.format('YYYY-MM-DD HH:mm:ss')); // 例如:2023-06-15 14:30:00
- // 相对时间
- console.log(moment('2023-06-10').fromNow()); // 例如:5 days ago
- // 本地化
- moment.locale('zh-cn');
- console.log(moment().format('LLLL')); // 例如:2023年6月15日星期四 下午2点30分
- // 日期计算
- console.log(moment().add(7, 'days').format('YYYY-MM-DD')); // 7天后的日期
- console.log(moment().subtract(1, 'month').format('YYYY-MM-DD')); // 1个月前的日期
复制代码
date-fns是现代JavaScript项目中推荐的日期库,它提供了模块化、不可变的日期处理功能:
- // 需要先安装date-fns
- // npm install date-fns
- import { format, addDays, subMonths, formatDistance } from 'date-fns';
- import { zhCN } from 'date-fns/locale';
- const now = new Date();
- // 格式化日期
- console.log(format(now, 'yyyy-MM-dd HH:mm:ss')); // 例如:2023-06-15 14:30:00
- // 本地化
- console.log(format(now, 'PPPP', { locale: zhCN })); // 例如:2023年6月15日星期四
- // 日期计算
- console.log(format(addDays(now, 7), 'yyyy-MM-dd')); // 7天后的日期
- console.log(format(subMonths(now, 1), 'yyyy-MM-dd')); // 1个月前的日期
- // 相对时间
- console.log(formatDistance(new Date(2023, 5, 10), now, {
- addSuffix: true,
- locale: zhCN
- })); // 例如:大约5天前
复制代码
Day.js是一个轻量级的日期库,API设计与Moment.js相似,但体积更小:
- // 需要先安装dayjs
- // npm install dayjs
- import dayjs from 'dayjs';
- import 'dayjs/locale/zh-cn';
- import relativeTime from 'dayjs/plugin/relativeTime';
- dayjs.locale('zh-cn');
- dayjs.extend(relativeTime);
- const now = dayjs();
- // 格式化日期
- console.log(now.format('YYYY-MM-DD HH:mm:ss')); // 例如:2023-06-15 14:30:00
- // 日期计算
- console.log(now.add(7, 'day').format('YYYY-MM-DD')); // 7天后的日期
- console.log(now.subtract(1, 'month').format('YYYY-MM-DD')); // 1个月前的日期
- // 相对时间
- console.log(dayjs('2023-06-10').fromNow()); // 例如:5天前
复制代码
时区处理
JavaScript中的时区问题
JavaScript的Date对象内部使用UTC时间(协调世界时),但在显示时会转换为本地时间。这可能导致一些意外的行为:
- // 创建UTC时间的Date对象
- const utcDate = new Date(Date.UTC(2023, 5, 15, 6, 30)); // 2023年6月15日 6:30 UTC
- // 在本地时区(例如东八区)显示
- console.log(utcDate.toString()); // 例如:Thu Jun 15 2023 14:30:00 GMT+0800 (中国标准时间)
- // 使用UTC方法获取时间组件
- console.log(utcDate.getUTCFullYear()); // 2023
- console.log(utcDate.getUTCMonth()); // 5 (六月)
- console.log(utcDate.getUTCDate()); // 15
- console.log(utcDate.getUTCHours()); // 6
- console.log(utcDate.getUTCMinutes()); // 30
- // 转换为ISO字符串(始终是UTC时间)
- console.log(utcDate.toISOString()); // 例如:2023-06-15T06:30:00.000Z
复制代码
处理不同时区的日期显示
在需要处理不同时区的应用中,可以使用Intl.DateTimeFormat API或第三方库:
- // 使用Intl.DateTimeFormat处理时区
- const now = new Date();
- const timeZoneOptions = {
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- hour: 'numeric',
- minute: 'numeric',
- second: 'numeric',
- timeZoneName: 'short'
- };
- // 纽约时间
- const newYorkFormatter = new Intl.DateTimeFormat('en-US', {
- ...timeZoneOptions,
- timeZone: 'America/New_York'
- });
- console.log('New York:', newYorkFormatter.format(now));
- // 伦敦时间
- const londonFormatter = new Intl.DateTimeFormat('en-GB', {
- ...timeZoneOptions,
- timeZone: 'Europe/London'
- });
- console.log('London:', londonFormatter.format(now));
- // 东京时间
- const tokyoFormatter = new Intl.DateTimeFormat('ja-JP', {
- ...timeZoneOptions,
- timeZone: 'Asia/Tokyo'
- });
- console.log('Tokyo:', tokyoFormatter.format(now));
复制代码
使用date-fns-tz库(date-fns的时区扩展)处理时区:
- // 需要安装date-fns-tz
- // npm install date-fns-tz
- import { format } from 'date-fns-tz';
- import { zhCN } from 'date-fns/locale';
- const now = new Date();
- // 格式化为不同时区的时间
- console.log(format(now, 'yyyy-MM-dd HH:mm:ss zzz', {
- timeZone: 'America/New_York'
- })); // 例如:2023-06-15 02:30:00 EDT
- console.log(format(now, 'yyyy-MM-dd HH:mm:ss zzz', {
- timeZone: 'Europe/London'
- })); // 例如:2023-06-15 07:30:00 BST
- console.log(format(now, 'yyyy-MM-dd HH:mm:ss zzz', {
- timeZone: 'Asia/Tokyo',
- locale: zhCN
- })); // 例如:2023-06-15 15:30:00 JST
复制代码
实际开发中的常见问题与解决方案
日期比较
在JavaScript中比较日期时,直接比较Date对象可能会得到意外的结果,应该比较它们的时间戳:
- const date1 = new Date('2023-06-15T14:30:00');
- const date2 = new Date('2023-06-15T14:30:00');
- // 错误的比较方式
- console.log(date1 == date2); // false,因为比较的是对象引用
- console.log(date1 === date2); // false,因为比较的是对象引用
- // 正确的比较方式 - 比较时间戳
- console.log(date1.getTime() === date2.getTime()); // true
- // 或者使用valueOf方法
- console.log(date1.valueOf() === date2.valueOf()); // true
- // 或者使用比较运算符(会自动转换为时间戳)
- console.log(date1 <= date2); // true
- console.log(date1 >= date2); // true
- // 比较日期部分(忽略时间)
- function isSameDay(date1, date2) {
- return date1.getFullYear() === date2.getFullYear() &&
- date1.getMonth() === date2.getMonth() &&
- date1.getDate() === date2.getDate();
- }
- console.log(isSameDay(date1, date2)); // true
复制代码
使用date-fns库进行日期比较:
- import { isSameDay, isBefore, isAfter, isWithinInterval } from 'date-fns';
- const date1 = new Date('2023-06-15T14:30:00');
- const date2 = new Date('2023-06-15T18:45:00');
- const date3 = new Date('2023-06-16T09:00:00');
- // 比较是否是同一天
- console.log(isSameDay(date1, date2)); // true
- console.log(isSameDay(date1, date3)); // false
- // 比较先后顺序
- console.log(isBefore(date1, date2)); // true
- console.log(isAfter(date2, date1)); // true
- // 检查日期是否在某个范围内
- const interval = {
- start: new Date('2023-06-15T00:00:00'),
- end: new Date('2023-06-15T23:59:59')
- };
- console.log(isWithinInterval(date1, interval)); // true
- console.log(isWithinInterval(date3, interval)); // false
复制代码
日期计算
JavaScript的Date对象提供了一些基本的日期计算方法,但对于复杂的计算,使用专门的库会更方便:
- // 使用原生Date对象进行简单计算
- const now = new Date();
- // 增加7天
- const nextWeek = new Date(now);
- nextWeek.setDate(now.getDate() + 7);
- // 减少1个月
- const lastMonth = new Date(now);
- lastMonth.setMonth(now.getMonth() - 1);
- // 计算两个日期之间的天数差
- function daysBetween(date1, date2) {
- const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
- const diffDays = Math.round(Math.abs((date1 - date2) / oneDay));
- return diffDays;
- }
- console.log(daysBetween(now, nextWeek)); // 7
复制代码
使用date-fns库进行日期计算:
- import {
- addDays,
- addWeeks,
- addMonths,
- addYears,
- subDays,
- differenceInDays,
- differenceInWeeks,
- differenceInMonths,
- differenceInYears,
- format,
- parseISO
- } from 'date-fns';
- const now = new Date();
- // 增加时间
- console.log(format(addDays(now, 7), 'yyyy-MM-dd')); // 7天后
- console.log(format(addWeeks(now, 2), 'yyyy-MM-dd')); // 2周后
- console.log(format(addMonths(now, 3), 'yyyy-MM-dd')); // 3个月后
- console.log(format(addYears(now, 1), 'yyyy-MM-dd')); // 1年后
- // 减少时间
- console.log(format(subDays(now, 7), 'yyyy-MM-dd')); // 7天前
- // 计算差值
- const futureDate = new Date('2024-06-15');
- console.log(differenceInDays(futureDate, now)); // 两个日期之间的天数差
- console.log(differenceInWeeks(futureDate, now)); // 两个日期之间的周数差
- console.log(differenceInMonths(futureDate, now)); // 两个日期之间的月数差
- console.log(differenceInYears(futureDate, now)); // 两个日期之间的年数差
- // 解析ISO字符串
- const isoString = '2023-06-15T14:30:00';
- const parsedDate = parseISO(isoString);
- console.log(format(parsedDate, 'yyyy-MM-dd HH:mm:ss')); // 2023-06-15 14:30:00
复制代码
性能优化
在处理大量日期数据时,性能可能成为一个问题。以下是一些优化建议:
- // 避免在循环中重复创建Date对象
- // 不好的做法
- for (let i = 0; i < 1000; i++) {
- const date = new Date(); // 每次循环都创建新的Date对象
- // 处理日期...
- }
- // 好的做法
- const now = new Date(); // 只创建一次Date对象
- for (let i = 0; i < 1000; i++) {
- // 使用now变量,而不是创建新的Date对象
- // 处理日期...
- }
- // 缓存格式化器
- // 不好的做法
- function formatDateBad(date) {
- return new Intl.DateTimeFormat('zh-CN', {
- year: 'numeric',
- month: 'long',
- day: 'numeric'
- }).format(date); // 每次调用都创建新的格式化器
- }
- // 好的做法
- const dateFormatter = new Intl.DateTimeFormat('zh-CN', {
- year: 'numeric',
- month: 'long',
- day: 'numeric'
- });
- function formatDateGood(date) {
- return dateFormatter.format(date); // 重用已创建的格式化器
- }
- // 使用轻量级库
- // Moment.js相对较大,而date-fns和Day.js更轻量
- // 对于只需要基本日期操作的项目,考虑使用更小的库或原生API
- // 批量处理日期数据
- const dates = [
- '2023-01-01',
- '2023-02-15',
- '2023-03-30',
- // ...更多日期
- ];
- // 不好的做法 - 多次调用格式化函数
- const formattedDatesBad = dates.map(dateStr => {
- return format(parseISO(dateStr), 'yyyy-MM-dd');
- });
- // 好的做法 - 使用更高效的方法
- const formatter = new Intl.DateTimeFormat('zh-CN', {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit'
- });
- const formattedDatesGood = dates.map(dateStr => {
- return formatter.format(new Date(dateStr));
- });
复制代码
最佳实践和总结
在JavaScript中处理日期时,遵循以下最佳实践可以帮助你避免常见问题并提高代码质量:
1. 了解你的需求:确定你需要简单的日期显示还是复杂的日期计算,以及是否需要国际化支持。
2. 选择合适的工具:对于简单的日期操作,使用原生Date对象和Intl.DateTimeFormat API。对于复杂的日期操作,考虑使用date-fns或Day.js等现代日期库。避免在新项目中使用Moment.js,因为它已进入维护模式。
3. 对于简单的日期操作,使用原生Date对象和Intl.DateTimeFormat API。
4. 对于复杂的日期操作,考虑使用date-fns或Day.js等现代日期库。
5. 避免在新项目中使用Moment.js,因为它已进入维护模式。
6. 正确处理时区:在服务器和客户端之间传递日期时,使用ISO 8601格式或时间戳。明确区分UTC时间和本地时间,使用相应的方法(getUTC* vs get*)。在需要显示不同时区时间的应用中,使用专门的时区处理库。
7. 在服务器和客户端之间传递日期时,使用ISO 8601格式或时间戳。
8. 明确区分UTC时间和本地时间,使用相应的方法(getUTC* vs get*)。
9. 在需要显示不同时区时间的应用中,使用专门的时区处理库。
10. 一致性和可读性:在整个项目中使用统一的日期格式。使用明确的变量名,如userBirthDate而不是date1。考虑创建专门的日期工具函数或类,封装常用的日期操作。
11. 在整个项目中使用统一的日期格式。
12. 使用明确的变量名,如userBirthDate而不是date1。
13. 考虑创建专门的日期工具函数或类,封装常用的日期操作。
14. 测试和边界情况:测试闰年、不同月份的天数、夏令时变化等边界情况。确保日期比较和计算在所有情况下都正确。
15. 测试闰年、不同月份的天数、夏令时变化等边界情况。
16. 确保日期比较和计算在所有情况下都正确。
17. 性能考虑:避免在循环中重复创建Date对象或格式化器。对于大量日期数据的处理,考虑使用批量处理或Web Worker。
18. 避免在循环中重复创建Date对象或格式化器。
19. 对于大量日期数据的处理,考虑使用批量处理或Web Worker。
了解你的需求:确定你需要简单的日期显示还是复杂的日期计算,以及是否需要国际化支持。
选择合适的工具:
• 对于简单的日期操作,使用原生Date对象和Intl.DateTimeFormat API。
• 对于复杂的日期操作,考虑使用date-fns或Day.js等现代日期库。
• 避免在新项目中使用Moment.js,因为它已进入维护模式。
正确处理时区:
• 在服务器和客户端之间传递日期时,使用ISO 8601格式或时间戳。
• 明确区分UTC时间和本地时间,使用相应的方法(getUTC* vs get*)。
• 在需要显示不同时区时间的应用中,使用专门的时区处理库。
一致性和可读性:
• 在整个项目中使用统一的日期格式。
• 使用明确的变量名,如userBirthDate而不是date1。
• 考虑创建专门的日期工具函数或类,封装常用的日期操作。
测试和边界情况:
• 测试闰年、不同月份的天数、夏令时变化等边界情况。
• 确保日期比较和计算在所有情况下都正确。
性能考虑:
• 避免在循环中重复创建Date对象或格式化器。
• 对于大量日期数据的处理,考虑使用批量处理或Web Worker。
示例:创建一个日期工具类
- class DateUtils {
- static #formatters = new Map();
-
- /**
- * 格式化日期
- * @param {Date|string|number} date - 日期对象、日期字符串或时间戳
- * @param {string} format - 格式模式
- * @param {string} [locale='zh-CN'] - 区域设置
- * @returns {string} 格式化后的日期字符串
- */
- static formatDate(date, format, locale = 'zh-CN') {
- const dateObj = typeof date === 'string' || typeof date === 'number'
- ? new Date(date)
- : date;
-
- if (isNaN(dateObj.getTime())) {
- throw new Error('Invalid date');
- }
-
- const formatterKey = `${locale}-${format}`;
- let formatter = this.#formatters.get(formatterKey);
-
- if (!formatter) {
- // 根据格式模式创建Intl.DateTimeFormat选项
- const options = this.#parseFormatPattern(format);
- formatter = new Intl.DateTimeFormat(locale, options);
- this.#formatters.set(formatterKey, formatter);
- }
-
- return formatter.format(dateObj);
- }
-
- /**
- * 解析格式模式为Intl.DateTimeFormat选项
- * @private
- * @param {string} format - 格式模式
- * @returns {Object} Intl.DateTimeFormat选项
- */
- static #parseFormatPattern(format) {
- // 这里实现一个简单的模式解析器
- // 实际实现可能更复杂,支持更多格式选项
- const options = {};
-
- if (format.includes('YYYY') || format.includes('YY')) {
- options.year = 'numeric';
- }
-
- if (format.includes('MM') || format.includes('M')) {
- options.month = format.includes('MMMM') ? 'long' :
- format.includes('MMM') ? 'short' : 'numeric';
- }
-
- if (format.includes('DD') || format.includes('D')) {
- options.day = 'numeric';
- }
-
- if (format.includes('HH') || format.includes('H')) {
- options.hour = 'numeric';
- options.hour12 = format.includes('h');
- }
-
- if (format.includes('mm') || format.includes('m')) {
- options.minute = 'numeric';
- }
-
- if (format.includes('ss') || format.includes('s')) {
- options.second = 'numeric';
- }
-
- return options;
- }
-
- /**
- * 检查两个日期是否是同一天
- * @param {Date|string|number} date1 - 第一个日期
- * @param {Date|string|number} date2 - 第二个日期
- * @returns {boolean} 如果是同一天则返回true
- */
- static isSameDay(date1, date2) {
- const d1 = typeof date1 === 'string' || typeof date1 === 'number'
- ? new Date(date1)
- : date1;
- const d2 = typeof date2 === 'string' || typeof date2 === 'number'
- ? new Date(date2)
- : date2;
-
- return d1.getFullYear() === d2.getFullYear() &&
- d1.getMonth() === d2.getMonth() &&
- d1.getDate() === d2.getDate();
- }
-
- /**
- * 计算两个日期之间的天数差
- * @param {Date|string|number} date1 - 第一个日期
- * @param {Date|string|number} date2 - 第二个日期
- * @returns {number} 天数差
- */
- static daysBetween(date1, date2) {
- const d1 = typeof date1 === 'string' || typeof date1 === 'number'
- ? new Date(date1)
- : date1;
- const d2 = typeof date2 === 'string' || typeof date2 === 'number'
- ? new Date(date2)
- : date2;
-
- // 将时间部分设置为0,只比较日期
- const oneDay = 24 * 60 * 60 * 1000;
- const firstDate = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate());
- const secondDate = new Date(d2.getFullYear(), d2.getMonth(), d2.getDate());
-
- return Math.round(Math.abs((firstDate - secondDate) / oneDay));
- }
-
- /**
- * 获取相对时间字符串(如"3天前")
- * @param {Date|string|number} date - 日期
- * @param {Date|string|number} [baseDate=new Date()] - 基准日期
- * @param {string} [locale='zh-CN'] - 区域设置
- * @returns {string} 相对时间字符串
- */
- static getRelativeTime(date, baseDate = new Date(), locale = 'zh-CN') {
- const dateObj = typeof date === 'string' || typeof date === 'number'
- ? new Date(date)
- : date;
- const baseObj = typeof baseDate === 'string' || typeof baseDate === 'number'
- ? new Date(baseDate)
- : baseDate;
-
- const formatterKey = `relative-${locale}`;
- let formatter = this.#formatters.get(formatterKey);
-
- if (!formatter) {
- formatter = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
- this.#formatters.set(formatterKey, formatter);
- }
-
- const diffInSeconds = Math.round((dateObj - baseObj) / 1000);
-
- // 定义时间单位及其秒数
- const units = [
- { unit: 'year', seconds: 60 * 60 * 24 * 365 },
- { unit: 'month', seconds: 60 * 60 * 24 * 30 },
- { unit: 'week', seconds: 60 * 60 * 24 * 7 },
- { unit: 'day', seconds: 60 * 60 * 24 },
- { unit: 'hour', seconds: 60 * 60 },
- { unit: 'minute', seconds: 60 },
- { unit: 'second', seconds: 1 }
- ];
-
- for (const { unit, seconds } of units) {
- const value = Math.abs(diffInSeconds) / seconds;
- if (value >= 1) {
- return formatter.format(Math.round(diffInSeconds / seconds) * -1, unit);
- }
- }
-
- return formatter.format(0, 'second');
- }
- }
- // 使用示例
- const now = new Date();
- const pastDate = new Date('2023-05-15');
- const futureDate = new Date('2023-07-15');
- console.log(DateUtils.formatDate(now, 'YYYY-MM-DD')); // 例如:2023-06-15
- console.log(DateUtils.formatDate(now, 'YYYY年MM月DD日')); // 例如:2023年06月15日
- console.log(DateUtils.formatDate(now, 'YYYY-MM-DD HH:mm', 'en-US')); // 例如:06/15/2023, 14:30
- console.log(DateUtils.isSameDay(now, new Date(now.getFullYear(), now.getMonth(), now.getDate()))); // true
- console.log(DateUtils.isSameDay(now, pastDate)); // false
- console.log(DateUtils.daysBetween(now, pastDate)); // 例如:31
- console.log(DateUtils.daysBetween(now, futureDate)); // 例如:30
- console.log(DateUtils.getRelativeTime(pastDate)); // 例如:1个月前
- console.log(DateUtils.getRelativeTime(futureDate)); // 例如:1个月内
复制代码
通过遵循这些最佳实践和使用适当的工具,你可以有效地处理JavaScript中的日期问题,创建出可靠、可维护的日期处理代码。无论是简单的日期显示还是复杂的日期计算,JavaScript都提供了足够的灵活性和功能来满足你的需求。 |
|