为了账号安全,请及时绑定邮箱和手机立即绑定

关于JavaScript中的Date你需要知道的一切

标签:
JavaScript C#

Date 对象在 JavaScript 中是非常奇怪的,以至于我们在处理时间和日期时,需要使用第三方库 date-fnsMoment 来处理。

但是并不是任何时候都需要引入这些库,如果你足够了解日期对象的话它其实很简单,在这篇文章中我将带你了解所有关于日期对象的信息。

首先,先从时区开始。

时区

世界上有几百个时区,但在 JavaScript 中,你只需要了解两个就行:当地时间和世界协调时(UTC)。

当地时间:指你的计算机所在的时区
世界协调时:是最主要的世界时间标准,是最接近格林威治标准时间(GMT),默认情况下,Date 对象创建的都是当地时间,只有在指定 UTC 时它才会创建世界协调时。

有了这个,就可以来谈论日期创建了。

创建日期

你可以通过 new Date() 来创建日期,它有四种使用方式:

  1. 日期字符串
  2. 日期参数
  3. 时间戳
  4. 无参数

1.日期字符串

new Date 传递一个日期字符串来创建

new Date('1988-03-21');

在创建日期时,我们倾向于这种日期字符串方法。因为这很自然符合我们的默认习惯。如果你写成 21-03-1988,在 JavaScript 中它是无效的。

原因是因为:

在世界上不同的地方,对日期字符有不同的理解,例如: 11-06-2019 你可以认为是 11th June, 2019 你也可以认为是 6th November 2019。如果不告诉你时间系统,根本无法得知到底该是哪个。

JavaScript 中,如果你想使用日期字符串,就必须使用一种全世界通用的格式,其中的一种格式就是 ISO 8601 Extended format

// ISO 8601 Extended format
`YYYY-MM-DDTHH:mm:ss:sssZ`

其中:

  • YYYY:4 位数的年份
  • MM:2 位数的月份(01-12)
  • DD:2 位数的日期(0-31)
  • -:日期分隔符
  • T:指示时间的开始
  • HH: 小时 (0 to 23)
  • mm: 分钟 (0 to 59)
  • ss: 秒数 (0 to 59)
  • sss: 毫秒 (0 to 999)
  • : :时间分隔符
  • Z:时区,有 Z 采用 UTC 时区,没有则是当地时区(仅限有时间的情况)

注意:原文中的 DD:2 位数的日期(0-31)有误,经求证 DD 应为 (01 to 31)可查看Date Time String Format

其中,小时、分钟、秒和毫秒是可选的。因此,如果想创建一个日期 2019年6月11日,你可以这么做:

new Date('2019-06-11')

请注意,如果你用 console.log 打印出这个日期,会发现存在一个很大的问题。

如果此时你在 GMT 时区「之后」的地区,得到的是:6月10日。

如果此时你是在 GMT 时区「之前」的地区,你得到的是:6月11日。

出现这种现象的原因是:当使用日期字符串时它会有一个特殊的行为:如果创建一个不指定时间的日期,它会以 UTC(世界协调时) 为时区。

所以如果你想创建本地时间,你需要加上 HHmm

new Date('2019-06-11T00:00')

通过上面能够看出使用日期字符串时,可能会因为本地时间和世界协调时出现何难捕捉的错误。

所以推荐你不要使用日期字符串来创建日期

顺便说一下,MDN 也警告不要使用日期字符串方法,因为浏览器可能会以不同的方式解析日期字符串。

如果要创建日期,请使用参数或时间戳。

2.参数

你最多可以传递 7 个参数来创建日期。

  • Year: 4 为数年份
  • Month: 月份 (0-11),默认值为 0
  • Day:天(1-31),默认值为 1
  • Hour:小时(0-23),默认值为 0
  • Minutes:分钟 (0-59),默认值为 0
  • Seconds:秒数(0-59),默认值为 0
  • Milliseconds: 毫秒数 (0-999),默认值为 0
// 11th June 2019, 5:23:59am, Local Time
new Date(2019, 5, 11, 5, 23, 59)

因为它看起来复杂,导致很多开发人员都不经常使用此方法来创建日期,但事实上却很简单。

它的参数从左到右分别为:年,月,日,时,分,秒,毫秒。就是这么简单。

new Date(2017, 3, 22, 5, 23, 50)

// This date can be easily read if you follow the left-right formula.
// Year: 2017,
// Month: April (because month is zero-indexed)
// Date: 22
// Hours: 05
// Minutes: 23
// Seconds: 50

唯一最大的问题就是月份的索引是从 0 开始的。如1月=== 0,2月=== 1,3月=== 2等等。

我们不知道为什么月份的索引是从 0 开始的,但确实如此,与其争论为什么不从 1 开始,不如试着去接收,一旦你接收了这个事实,它就变得容易多了。

通过几个例子熟悉一下:

// 21st March 1988, 12am, Local Time.
new Date(1988, 2, 21)

// 25th December 2019, 8am, Local Time.
new Date(2019, 11, 25, 8)

// 6th November 2023, 2:20am, Local Time
new Date(2023, 10, 6, 2, 20)

// 11th June 2019, 5:23:59am, Local Time
new Date(2019, 5, 11, 5, 23, 59)

你会发现使用参数创建的时间都是本地时间,这也是它的好处之一,不会像日期字符串那样会产生不同的结果。

如果你想创建UTC(世界协调时)的话,可以这么做:

// 11th June 2019, 12am, UTC.
new Date(Date.UTC(2019, 5, 11))

3.时间戳

在 JavaScript 中,时间戳是指自1970年1月1日到现在的毫秒数。据我的经验很少有人用它来创建日期,因为这个数字往往大的惊人,很不好计算。更多的是使用它来比较两个日期的大小。

// 11th June 2019, 8am (in my Local Time, Singapore)
new Date(1560211200000)

4.无参数

如果创建不带有任何的参数,它会返回当前的日期(本地时间)

new Date()

总结

  1. 你可以通过 new Date()来创建一个日期
  2. 有四种语法可以创建:
    • 日期字符串
    • 日期参数
    • 时间戳
    • 无参数
  3. 不推荐使用日期字符串,因为它会有不同的结果。
  4. 最好的方式是使用参数方式创建,分别对应为:年,月,日,时,分,秒,毫秒
  5. 记住用参数创建时月份的索引从0开始。

接下来我们来谈谈日期格式的转换。

格式化日期

在其他语言中会提供格式化工具来创建一个你想要的日期格式,例如:在 PHP 中你可以用 date("d M Y") 来创建一个像23 Jan 2019这种格式的。

但是在 JavaScript 中格式化日期并没有简单的方法。原生 Date 对象提供了 7 种格式化的方法,但是这 7 种方法返回的都是一个特定的值,并无使用价值。

const date = new Date(2019, 0, 23, 17, 23, 42)
  1. toString:返回 Wed Jan 23 2019 17:23:42 GMT+0800 (中国标准时间)
  2. toDateString:Wed Jan 23 2019
  3. toLocaleString:返回 23/01/2019, 17:23:42
  4. toLocaleDateString:23/01/2019
  5. toGMTString:Wed, 23 Jan 2019 09:23:42 GMT
  6. toUTCString:Wed, 23 Jan 2019 09:23:42 GMT
  7. toISOString:2019-01-23T09:23:42.079Z

如果想要一个自定义的值,此时就需要自己动手实现。

自定义格式

比如你想要一个像 Thu, 23 January 2019这种日期,你需要用到下面四种方法:

  1. getFullYear:根据当地时间获取4位数的年份
  2. getMonth:根据当地时间获取一年中的月份(0-11)。月份是零索引的
  3. getDate:根据当地时间获取一个月中的某一天(1-31)
  4. getDay:根据当地时间获取一周中的某一天(0-6)。一周中的一天从星期日(0)开始,到星期六(6)结束。

获取年份和日期非常简单,直接使用 getFullYeargetDate即可。

const d = new Date(2019, 0, 23)
const year = d.getFullYear() // 2019
const date = d.getDate() // 23

难的是获取ThuJanuary

想要获取January可以创建一个对象,然后让十二个月的值映射到各自的名称上。

const months = {
  0: 'January',
  1: 'February',
  2: 'March',
  3: 'April',
  4: 'May',
  5: 'June',
  6: 'July',
  7: 'August',
  8: 'September',
  9: 'October',
  10: 'November',
  11: 'December'
}

因为月份的索引是从 0 开始的,所以我们可以使用数组来代替对象,其结果是一样的。

const months = [
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December'
]

获取January,你需要:

  1. 使用 getMonth获取到索引
  2. 从 months 获取到名称。
const monthIndex = d.getMonth()
const monthName = months[monthIndex]
console.log(monthName) // January

可合并为

const monthName = months(d.getMonth())
console.log(monthName) // January

同样的你可以用相同的方式来获取到 Thu

const days = [
  'Sun',
  'Mon',
  'Tue',
  'Wed',
  'Thu',
  'Fri',
  'Sat'
]

然后:

  1. 使用 getDay 获取索引
  2. 从 days 获取到名称。
const dayName = days[d.getDay()] // Thu

至此,我们把上面的字符全部连接起来,就可以得到想要的结果。

const formatted = `${dayName}, ${date} ${monthName} ${year}`
console.log(formatted) // Thu, 23 January 2019

如果想创建自定义时间格式,可以用下面几个方法:

  • getHours:根据当地时间获取小时数(0-23)。
  • getMinutes: 根据当地时间获取分钟数(0-59)。
  • getSeconds: 根据当地时间获取秒(0-59)。
  • getMilliseconds: 根据本地时间获取毫秒(0-999)。

接下来,我们来继续谈日期的比较。

日期比较

如果想比较两个日期的大小,可直接使用比较符 >、<、>=、<= 。

const earlier = new Date(2019, 0, 26)
const later = new Date(2019, 0, 27)

console.log(earlier < later) // true

但如果你想比较两个日期是否相等,此时使用 == 或 === 却无能为力了。

const a = new Date(2019, 0, 26)
const b = new Date(2019, 0, 26)

console.log(a == b) // false
console.log(a === b) // false

想要比较两个日期是否相等,可以使用 getTime 来获取时间戳来进行比较。

const isSameTime = (a, b) => {
  return a.getTime() === b.getTime()
}

const a = new Date(2019, 0, 26)
const b = new Date(2019, 0, 26)
console.log(isSameTime(a, b)) // true

如果想检查两个日期是否在同一天,可以检查它们的 getFullYear、getMonth 和 getDate 的值。

const isSameDay = (a, b) => {
  return a.getFullYear() === b.getFullYear() &&
    a.getMonth() === b.getMonth() &&
    a.getDate()=== b.getDate()
}

const a = new Date(2019, 0, 26, 10) // 26 Jan 2019, 10am
const b = new Date(2019, 0, 26, 12) // 26 Jan 2019, 12pm
console.log(isSameDay(a, b)) // true

最后我们在谈一件事

计算日期

有两种可能的情况:

  1. 设置特定日期/时间
  2. 增加/减少日期

设定特定日期

你可以用以下方法设定日期:

  1. setFullYear:设置年份
  2. setMonth:设置月份
  3. setDate:设置天
  4. setHours:设置时
  5. setMinutes:设置分钟
  6. setSeconds:设置秒数
  7. setMilliseconds:设置毫秒数

例如可以将日期设置为 15号:

const d = new Date(2019, 0, 10)
d.setDate(15)

console.log(d) // 15 January 2019

如果想将月份设置为 6 月,可以用 setMonth (月的索引要从 0 开始)

const d = new Date(2019, 0, 10)
d.setMonth(5)

console.log(d) // 10 June 2019

注意:上面的方法我们都修改了原始的对象,实际上我们不应该这么改变对象为什么在这里,应该创建一个新的对象进行操作。

const d = new Date(2019, 0, 10)
const newDate = new Date(d)
newDate.setMonth(5)

console.log(d) // 10 January 2019
console.log(newDate) // 10 June 2019

增加/减少 日期

想要计算改变后的日期,首先你需要获取到它们:

  1. getFullYear:根据当地时间获取4位数的年份
  2. getMonth:根据当地时间获取一年中的月份(0-11)。月份是零索引的
  3. getDate:根据当地时间获取一个月中的某一天(1-31)
  4. getHours:根据当地时间获取小时数(0-23)。
  5. getMinutes: 根据当地时间获取分钟数(0-59)。
  6. getSeconds: 根据当地时间获取秒(0-59)。
  7. getMilliseconds: 根据本地时间获取毫秒(0-999)。

通常有两种方法实现日期的增加或减少。第一种:简介但难理解,第二种,冗长但好理解。

一起来看

假设现在是2019年3月28日,我想要得到三天后的日期。

第一种方法:

const today = new Date(2019, 2, 28)
const finalDate = new Date(today)
finalDate.setDate(today.getDate() + 3)

console.log(finalDate) // 31 March 2019

第二种方法:

在这里,我们使用getFullYear、getMonth、getDate 和其他getter方法,直到找到想要更改的值的类型。然后我们用新日期创建最终日期。

const today = new Date(2019, 2, 28)

// Getting required values
const year = today.getFullYear()
const month = today.getMonh()
const day = today.getDate()

// Creating a new Date (with the delta)
const finalDate = new Date(year, month, day + 3)

console.log(finalDate) // 31 March 2019

以上两种方式都是有效的,你可以选择一种去做。

自动修正

如果你提供的日期值超出了其可接受的范围,JavaScript 会自动重新计算日期。

比如:把日期定在2019年3月33日,在这种情况下,JavaScript会自动将3月33日调整到4月2日。

// 33rd March => 2nd April
new Date(2019, 2, 33)

这意味着我们不需要担心计算分钟、小时、天、月等。 JavaScript 会自动帮助我们处理。

// 33rd March => 2nd April
new Date(2019, 2, 30 + 3)

到这里,有关于日期对象的所有东西你都已经了解啦。

我是一名爱写作的技术人。
关注公众号:六小登登,后台回复「1024」即可免费获取惊喜福利!后台回复「加群」群里每天都会全网搜罗好文章给你。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
3975
获赞与收藏
1285

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消