new Date() 构造函数是魔鬼 - 哦,我害怕它!这导致我在工作中犯了很多错误,其中一些非常奇怪。
我们必须非常小心地对待它,否则我们很容易陷入它的陷阱。
1. Safari浏览器不支持YYYY-MM-DD形式的格式化日期
你知道吗?“Safari”浏览器不支持“YYYY-MM-DD”形式的初始化时间。除它之外的很多浏览器,例如Chrome浏览器,都完美支持这种格式。
如果您编写这样的代码,您的应用程序将在“Safari”浏览器中收到无效日期错误。
new Date('2023-05-28') // Invalid Date
为了正确处理这个问题,我们需要以“YYYY/MM/DD”的形式初始化时间。
new Date('2023/05/28')
2.使用0作为月份的起始索引
我们应该如何初始化日期 2023 年 5 月 28 日?
const d = new Date(2023, 4, 28)
console.log(d.getMonth()) // 4
我们将 4 作为第二个参数传递给 Date,但为什么不传递 5?
啊! 我讨厌这个功能。处理月份时,日期以 0 开头,0 表示一月,1 表示二月,等等。这个函数很糟糕,非常混乱且有错误。
3.关于其自动日期校正的陷阱
很难猜测下面的代码代表的真实日期是什么。
也许是 2023 年 2 月的日期?但二月并没有32天,很奇怪,那么到底是什么呢?
const d = new Date(2023, 1, 32)
让我们编写一个解析日期对象的函数。
const parseDate = (date) => {
const year = date.getFullYear()
const month = date.getMonth() + 1 //Since the index of the month starts from 0, we need to add 1
const day = date.getDate()
return { year, month, day }
}
console.log(parseDate(new Date(2023, 1, 32)))
/*
{
"year": 2023,
"month": 3,
"day": 4
}
*/
哦,新的日期(2023, 1, 32)是2023年3月4日,这太离谱了。
4. 无法轻松格式化日期?
如何将数组转换为指定格式的字符串?很简单,我们可以使用数组的join方法。
const array = [ '2023', '5', '28' ]
console.log(array.join('/')) // 2023/5/28
console.log(array.join('-')) // 2023-5-28
console.log(array.join(':')) // 2023:5:28
但是Date对象并没有提供直接方便的方式来格式化日期,所以我们必须自己编写代码来实现。
const formatDate = (date, format = '/') => {
return date.getFullYear() + format + (date.getMonth() + 1) + format + date.getDate()
}
formatDate(new Date(2023, 4, 28), ':') // 2023:5:28
formatDate(new Date(2023, 4, 28), '/') // 2023/5/28
formatDate(new Date(2023, 4, 28), ':') // 2023-5-28
5. 无法确定日期对象是否有效
就像上面的例子一样,由于Date对象会自动固定日期,所以,我们无法判断一个日期是否真的有效。
const d = new Date(2023, 15, 1) // this is a date that does not exist
formatDate(d) // 2024/4/1
6. string类型的日期无法正确解析
很多时候我们会通过传递日期字符串来初始化日期,因为它比 new Date(2023, 4, 28) 使用起来方便得多。
const d1 = new Date('2023-5-28')
console.log(formatDate(d1)) // 2023/5/28
这里也有陷阱,我的朋友,我们必须小心。
const d2 = new Date('5-28-2023')
console.log(formatDate(d2)) // 2023/5/28
如果您传入这样的日期,您将收到无效错误警告。
const d3 = new Date('28-5-2023') // Invalid Date
const d4 = new Date('2023-28-5') // Invalid Date
7. 无法判断Date是否为闰年
哇,有时我们需要在工作中确定一年是否是闰年,这有点麻烦,因为 Date 对象也没有提供执行此操作的对象方法。
const isLeapYear = (date) => {
const year = date.getFullYear()
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
}
isLeapYear(new Date(2023, 4, 28)) // false
isLeapYear(new Date(2020, 4, 28)) // true
8. 新日期(xx, xx, xx) 是一年中的哪一周?
Date对象提供了获取年、月、日、小时、分钟等的函数。
我们如何确定日期是一年中的第几周?我们只能通过复杂的计算来完成这个目标。
const getWeekNumber = (date) => {
// Creates a new Date object, set to a copy of the given date
const newDate = new Date(date.getTime())
// Set the time part of the date object to 0 so that only the date is considered
newDate.setHours(0, 0, 0, 0)
// Sets the date object to the first day of the year
newDate.setDate(1)
newDate.setMonth(0)
// Gets the day of the week for the first day (0 for Sunday, 1 for Monday, etc.
const firstDayOfWeek = newDate.getDay()
// Calculates the difference in days from a given date to the start of the first week
const diff = (date.getTime() - newDate.getTime()) / (24 * 60 * 60 * 1000)
// Determines the start date of the first week according to the ISO 8601 standard
let weekStart = 1 - firstDayOfWeek
if (firstDayOfWeek > 4) {
weekStart += 7 // If the first day is a Friday or later, move the first week back by one week
}
// Calculate week number (rounded down)
const weekNumber = Math.floor((diff + weekStart) / 7) + 1
return weekNumber
}
getWeekNumber(new Date(2023, 4, 28)) // 22
这是一种常见的计算,使用 ISO 8601 标准来计算日期是一年中的第几周。
但显然,它太复杂了,我无法理解这个功能。
写在最后
Date对象有很多奇怪的行为,我们可以使用一些强大的库来帮助我们。例如Moment.js、Day.js、date-fns等。