在JavaScript中进行日期操作 - 一个完整的指南

175 阅读10分钟

JavaScript中的日期操作--完整指南

学习如何在JavaScript中处理日期和时间

从理论上讲,作为一个开发人员,处理日期就像创建、存储以及必要时操作日期一样简单。但作为一个Javascript开发者,你会知道,当你开始真正处理日期时,这个理论并不成立。除了不同的日期时间格式外,你还必须考虑时区和地域差异。

由于这个原因,很多Javascript开发者在应用程序中管理日期时,都会寻求第三方库的帮助。虽然这些库降低了任务的复杂性,但对处理虚无缥缈的Javascript日期有清晰的认识也有好处。

本教程将向你介绍如何在vanilla Javascript中处理日期,以及有用的第三方库来帮助你简化更复杂的日期相关任务。


Javascript的日期对象

当涉及到处理日期和时间时,Javascript中的Date对象是主要元素。它记录了一个单一的时间点,即自1970年1月1日00:00:00(UTC)以来所经过的毫秒数。这种日期-时间组合被称为 "纪元时间"。就Javascript而言,它是世界上时间的开始。


创建日期

你可以使用new Date() ,简单地创建一个日期。你可以向Date构造函数传递参数来创建一个你选择的日期。给定的参数可以采取不同的形式。

传递一个日期字符串

在创建一个新的Date对象时,你可以传递一个公认格式的日期字符串:

const date = new Date("2020-12-31");

现在,如果我们打印创建的日期,它显示的是这样的:

Thu Dec 31 2020 01:00:00 GMT+0100 (Central European Standard Time)

除了我们传递的日期之外,日期对象还有更多的值,包括时间和时区。由于我们在创建对象时没有给这些参数一个具体的值,所以Javascript使用代码系统的本地时间和时区。

如果我们想用参数字符串传递时间或时区,我们可以使用这样的格式。

YYYY-MM-DDTHH:mm:ss.ssZ

  • YYYY:年
  • MM:月(1到12)
  • DD:日期(1至31)
  • HH:24小时格式的小时(0至23)
  • mm:分钟(0到59)
  • ss:秒(00至59)
  • sss:毫秒(0至999)
  • T用于分隔字符串中的日期和时间
  • 如果出现Z,则假定时间为UTC。否则,它假定为当地时间。

然而,如果T和Z不存在,字符串的创建日期在不同的浏览器中可能会出现不同的结果。在这种情况下,为了使日期总是有相同的时区,可以在最后加上+HH:mm-HH:mm

let newDate = new Date("2021-09-23T23:45Z")
// Fri Sep 24 2021 01:45:00 GMT+0200 (Central European Summer Time)

newDate = new Date("2021-09-23T23:45");
// Thu Sep 23 2021 23:45:00 GMT+0200 (Central European Summer Time)

newDate = new Date("2021-09-23T23:45+05:30")
// Thu Sep 23 2021 20:15:00 GMT+0200 (Central European Summer Time)

你可以使用Date.parse 函数来获得同样的结果,而不是将日期字符串传递给Date构造函数。每当你传递一个日期字符串时,Date.parse 在构造函数中被间接地调用。

这些字符串中使用的格式是ISO 8601日历扩展格式。你可以参考ECMAScript规范中的细节。

传递日期参数

你可以直接向Date构造函数传递日期参数,而不必使用混乱的日期字符串。每一个年、月等的顺序和长度都与日期字符串中的完全一样:

let newDate = new Date(1998, 9, 30, 13, 40, 05);

当我们检查创建的日期的结果时,我们可以注意到最后的日期有一个关键的不同:

Fri Oct 30 1998 13:40:05 GMT+0100 (Central European Standard Time)

有什么奇怪的?当我们创建日期时,我们用9来表示月份,我们可以认为是九月。然而,当我们打印结果时,月份却变成了十月。这是为什么呢?

Javascript使用一个基于零的索引来识别一年中的每个月。这意味着,对于Javascript来说,一月是用0而不是1来表示的,同样,十月是用9而不是10来表示的。

在这种创建日期的方法中,我们不能传递一个参数来表示其时区。所以,它被默认为系统的本地时间。但是我们可以使用Date.UTC 函数将日期转换为UTC,然后再传递给Date构造函数:

newDate = new Date(Date.UTC(1998, 09, 30, 13, 40, 05))
// Fri Oct 30 1998 14:40:05 GMT+0100 (Central European Standard Time)

传递一个时间戳

还记得我提到Javascript在Date对象中存储了自纪元时间以来所经过的时间吗?我们可以传递这个经过的时间值,称为时间戳,来表示我们正在创建的日期。

newDate = new Date(1223727718982)
// Sat Oct 11 2008 14:21:58 GMT+0200 (Central European Summer Time)

为当前日期和时间创建一个Date对象

如果你想为系统的当前日期和时间创建一个Date对象,请使用Date构造函数,不要传递任何参数:

let now = new Date()
// Sat Jan 09 2021 22:06:33 GMT+0100 (Central European Standard Time)

你也可以使用Date.now() 函数来完成同样的任务:

now = Date.now()

格式化日期

Javascript提供了几个内置函数来格式化一个日期。然而,这些函数只是将日期转换为每个函数的特定格式。

让我们来看看每个格式化函数是如何工作的:

let newDate = new Date("2021-01-09T14:56:23")

newDate.toString()
// "Sat Jan 09 2021 14:56:23 GMT+0100 (Central European Standard Time)"

newDate.toDateString()
// "Sat Jan 09 2021"

newDate.toLocaleDateString()
// "1/9/2021"

newDate.toLocaleTimeString()
// "2:56:23 PM"

newDate.toLocaleString()
// "1/9/2021, 2:56:23 PM"

newDate.toGMTString()
// "Sat, 09 Jan 2021 13:56:23 GMT"

newDate.toUTCString()
// "Sat, 09 Jan 2021 13:56:23 GMT"

newDate.toISOString()
// "2021-01-09T13:56:23.000Z"

newDate.toTimeString()
// "14:56:23 GMT+0100 (Central European Standard Time)"

newDate.getTime()
// 1610200583000

国际化API

ECMAScript国际化API允许使用Intl对象将日期格式化为一个特定的区域:

let newDate = new Date("2021-01-09T14:56:23")

//format according to the computer's default locale
Intl.DateTimeFormat().format(newDate)
// "1/9/2021"

//format according to a specific locale, e.g. de-DE (Germany)
Intl.DateTimeFormat("de-DE").format(newDate)
// "9.1.2021"

你可以给DateTimeFormat函数传递一个options对象,以显示时间值和自定义输出:

let options = {
    year: "numeric",
    month: "long",
    weekday: "long",
    hour: "numeric",
    minute: "numeric",
}

Intl.DateTimeFormat("en-US", options).format(newDate)
// "January 2021 Saturday, 2:56 PM"

自定义日期格式

如果你想将日期格式化为这些函数所提供的以外的任何其他格式,你必须通过单独访问日期的每一部分并将它们结合起来来实现。

Javascript提供了以下函数,可以从Date对象中检索出年、月、日期和日:

newDate.getFullYear() // 2021
newDate.getMonth()    // 0 (zero-based index)
newDate.getDate()     // 9
newDate.getDay()      // 6 (zero-based index starting from Sunday)
newDate.getHours()    // 14
newDate.getMinutes()  // 56
newDate.getUTCHours() // 9
newDate.getUTCDate()  // 9

现在,你可以使用检索到的部分将日期转换为自定义格式。


更新日期

Javascript提供了几种方法来编辑一个已经创建的日期:

newDate = new Date("2021-01-08T22:45:23")

newDate.setYear(1998)
//Thu Jan 08 1998 22:45:23 GMT+0100 (Central European Standard Time)

newDate.setMonth(4)
//Fri May 08 1998 22:45:23 GMT+0200 (Central European Summer Time)

newDate.setDate(12)
//Tue May 12 1998 22:45:23 GMT+0200 (Central European Summer Time)

newDate.setHours(12)
newDate.setMinutes(21)
newDate.setUTCDate(26)
newDate.setUTCMinutes(56)

比较日期

如果你想知道一个特定的日期是否在另一个之前,你可以直接使用大于和小于运算符进行比较:

let first = new Date(2010, 3, 19)
let second = new Date(2010, 3, 24)

first > second      //false

但是,如果你想检查它们是否相等,无论是==还是===运算符都不能如愿:

first = new Date(2009, 12, 23)
second = new Date(2009, 12, 23)

console.log(first == second)  // false
console.log(first === second) // false

相反,你必须检索每个日期的时间戳并比较它们是否相等。

first.getTime() === second.getTime() // true

这是因为JavaScript中的日期是对象,所以每个日期都有一个不同的类的实例,而===== 操作符是在比较内存地址,而不是日期的实际值。


Javascript的日期操作库

我们可以找到几个Javascript日期和时间操作库,作为开源项目或其他。其中有些是为所有种类的日期时间操作而设计的,有些则有一套特定的用例。在本节中,我将只谈流行的多用途库。

Moment.js曾经是Javascript开发者中的日期操作库之王。然而,它的开发者最近宣布,它正专注于维护当前的代码库而不是增加新的功能。他们建议为那些正在进行新项目的人寻找一个替代解决方案。

那么,除了Moment.js,我们还可以使用哪些库来使我们的开发者的生活更轻松呢?

日期-fns

Date-fns是一个开源的库,支持日期解析和格式化、地域性以及加减法等日期运算。由于其通用性,它被称为日期的Lodash:

const datefns = require("date-fns");

let date = datefns.format(new Date(2017, 09, 12), "dd MMM yyyy");
date = datefns.format(new Date(2017, 09, 12), "dd.MM.yy");

正如你所看到的,你可以通过传递一个简单的格式化字符串,轻松地将一个日期转换成你喜欢的格式:

它还允许我们轻松地添加和减去日期。

let date = new Date(2019, 09, 22)

let newDate1 = datefns.addDays(date, 21)
let newDate2 = datefns.addYears(date, 2)
let newDate3 = datefns.subMonths(date, 3)

console.log(datefns.format(newDate1, 'dd/MM/yyyy')) // 12/11/2019
console.log(datefns.format(newDate2, 'dd/MM/yyyy')) // 22/10/2021
console.log(datefns.format(newDate3, 'dd/MM/yyyy')) // 22/07/2019

Luxon

Luxon是一个日期时间操作库,由Moment.js的一个开发者创建,以适应现代应用的要求。与Date-fns类似,Luxon提供数据格式化和解析功能。此外,它还具有原生的国际化支持,并且是可连锁的。

let date = DateTime.local(2019, 08, 12)

console.log(date.toLocaleString(DateTime.DATETIME_FULL))
console.log(date.toLocaleString(DateTime.DATETIME_MED))

你还可以测量两个日期之间的时间间隔。

let now = DateTime.local()
let later = DateTime.local(2021, 03, 12)

console.log(Interval.fromDateTimes(now, later).length('years'))

总结

本教程讨论了如何在有或没有外部库的情况下在Javascript中处理日期和时间。在几乎所有的编程语言中,处理日期总是很痛苦。幸运的是,JS和它的库的生态系统为我们做了所有繁重的工作,使我们能够专注于构建功能。

谢谢你的阅读!