八個關(guān)于 new Date() 的陷阱,你需要知道一下
new Date() 構(gòu)造函數(shù)是魔鬼 - 哦,我害怕它!這導(dǎo)致我在工作中犯了很多錯誤,其中一些非常奇怪。
我們必須非常小心地對待它,否則我們很容易陷入它的陷阱。
1. Safari瀏覽器不支持YYYY-MM-DD形式的格式化日期
你知道嗎?“Safari”瀏覽器不支持“YYYY-MM-DD”形式的初始化時間。除它之外的很多瀏覽器,例如Chrome瀏覽器,都完美支持這種格式。
如果您編寫這樣的代碼,您的應(yīng)用程序?qū)⒃凇癝afari”瀏覽器中收到無效日期錯誤。
new Date('2023-05-28') // Invalid Date
為了正確處理這個問題,我們需要以“YYYY/MM/DD”的形式初始化時間。
new Date('2023/05/28')
2.使用0作為月份的起始索引
我們應(yīng)該如何初始化日期 2023 年 5 月 28 日?
const d = new Date(2023, 4, 28)
console.log(d.getMonth()) // 4
我們將 4 作為第二個參數(shù)傳遞給 Date,但為什么不傳遞 5?
啊! 我討厭這個功能。處理月份時,日期以 0 開頭,0 表示一月,1 表示二月,等等。這個函數(shù)很糟糕,非常混亂且有錯誤。
3.關(guān)于其自動日期校正的陷阱
很難猜測下面的代碼代表的真實日期是什么。
也許是 2023 年 2 月的日期?但二月并沒有32天,很奇怪,那么到底是什么呢?
const d = new Date(2023, 1, 32)
讓我們編寫一個解析日期對象的函數(shù)。
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. 無法輕松格式化日期?
如何將數(shù)組轉(zhuǎn)換為指定格式的字符串?很簡單,我們可以使用數(shù)組的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對象并沒有提供直接方便的方式來格式化日期,所以我們必須自己編寫代碼來實現(xiàn)。
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 對象也沒有提供執(zhí)行此操作的對象方法。
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對象提供了獲取年、月、日、小時、分鐘等的函數(shù)。
我們?nèi)绾未_定日期是一年中的第幾周?我們只能通過復(fù)雜的計算來完成這個目標(biāo)。
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 標(biāo)準(zhǔn)來計算日期是一年中的第幾周。
但顯然,它太復(fù)雜了,我無法理解這個功能。
寫在最后
Date對象有很多奇怪的行為,我們可以使用一些強大的庫來幫助我們。例如Moment.js、Day.js、date-fns等。