• 需要日期对象时为什么我建议使用Moment.js等日期库来替代原生new Date() 函数
  • 发布于 2个月前
  • 212 热度
    0 评论
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 日?
// 堆代码 duidaima.com
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等。
用户评论