JavaScript日期时间操作完整指南!(下)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: JavaScript日期时间操作完整指南!(下)

JavaScript日期时间操作完整指南!(上)https://developer.aliyun.com/article/1411542


日期/时间操作最佳实践

从用户获取日期和时间

如果需要从用户那里获取日期和时间,那么很可能需要的是他们的本地日期时间。我们在日期计算部分看到Date构造函数可以接受多种不同的日期格式。

为了消除任何混淆,建议使用new Date(year, month, day, hours, minutes, seconds, milliseconds)格式来创建日期,这是使用Date构造函数时能够做到的最明确的方式。

可以使用允许省略最后四个参数的变体,如果它们为零;例如,new Date(2012, 10, 12)new Date(2012, 10, 12, 0, 0, 0, 0)是相同的,因为未指定的参数默认为零。

例如,如果正在使用一个日期和时间选择器,它给出了日期2012-10-12和时间12:30,可以提取这些部分并创建一个新的Date对象,如下所示:

javascript

复制代码

const datePickerDate = '2012-10-12';
const timePickerTime = '12:30';
const [year, month, day] = datePickerDate.split('-').map(Number);
const [hours, minutes] = timePickerTime.split(':').map(Number);
const dateTime = new Date(year, month - 1, day, hours, minutes);
console.log(dateTime); // Fri Oct 12 2012 12:30:00 GMT+0800 (中国标准时间)

在上述示例中,首先将日期和时间分别存储在datePickerDatetimePickerTime变量中。然后,使用split()方法将日期字符串和时间字符串拆分为数值数组,并将其存储在[year, month, day][hours, minutes]变量中。最后,使用这些值创建一个新的Date对象,注意按照 JavaScript 的月份规则,需要将月份减去1。这样就得到了一个包含用户所选日期和时间的Date对象。

通过遵循这种方法,可以明确地指定日期和时间,以便消除不同日期解析格式可能带来的混乱。

javascript

复制代码

const dateFromPicker = "2012-10-12";
const timeFromPicker = "12:30";
const dateParts = dateFromPicker.split("-");
const timeParts = timeFromPicker.split(":");
const localDate = new Date(dateParts[0], dateParts[1]-1, dateParts[2], timeParts[0], timeParts[1]);

注意,尽量避免从字符串创建日期,除非它是 ISO 日期格式。 请改用 Date(year, month, date, hours, minutes, seconds, microseconds) 方法。

仅获取日期

如果只获取日期(例如用户的生日),最好将格式转换为有效的 ISO 日期格式,以消除任何可能导致日期在转换为 UTC 时向前或向后移动的时区信息。 例如:

javascript

复制代码

const dateFromPicker = "12/20/2012";
const dateParts = dateFromPicker.split("/");
const ISODate = dateParts[2] + "-" + dateParts[0] + "-" + dateParts[1];
const birthDate = new Date(ISODate).toISOString();

如果使用有效的 ISO 日期格式 (YYYY-MM-DD) 输入创建一个 Date 对象,它将默认为 UTC,而不是默认为浏览器的时区。

存储日期

始终以 UTC 格式存储日期时间,始终将 ISO 日期字符串或时间戳保存到数据库。实践证明,在后端存储本地时间是一个坏主意,最好让浏览器在前端处理到本地时间的转换。不应该将“July 20, 1989 12:10 PM”之类的日期时间字符串发送到后端。

可以使用 Date 对象的 toISOString()toJSON() 方法将本地时间转换为 UTC。

javascript

复制代码

const dateFromUI = "12-13-2012";
const timeFromUI = "10:20";
const dateParts = dateFromUI.split("-");
const timeParts = timeFromUI.split(":");
const date = new Date(dateParts[2], dateParts[0]-1, dateParts[1], timeParts[0], timeParts[1]);
const dateISO = date.toISOString();
$.post("http://example.com/", {date: dateISO}, ...)

显示日期和时间

  1. 从 API 获取时间戳或 ISO 格式的日期。
  2. 创建一个日期对象。
  3. 使用 toLocaleString()toLocaleDateString()toLocaleTimeString() 方法或日期库来显示本地时间。

javascript

复制代码

const dateFromAPI = "2016-01-02T12:30:00Z";
const localDate = new Date(dateFromAPI);
const localDateString = localDate.toLocaleDateString(undefined, {  
    day:   'numeric',
    month: 'short',
    year:  'numeric',
});
const localTimeString = localDate.toLocaleTimeString(undefined, {
    hour:   '2-digit',
    minute: '2-digit',
    second: '2-digit',
});

现代日期/时间处理 API:Temporal

JavaScript 中的日期处理 Date() 对象一直是饱受诟病,该对象是1995 年受到 Java 的启发而实现的,自此就一直没有改变过。虽然Java已经放弃了这个对象,但是 Date() 仍保留在 JavaScript 中来实现浏览器的兼容。

Date() API 存在的问题:

  • 只支持UTC和用户的PC时间;
  • 不支持公历以外的日历;
  • 字符串到日期解析容易出错;
  • Date 对象是可变的,比如:

javascript

复制代码

const today = new Date();
const tomorrow = new Date(today.setDate(today.getDate() + 1));
console.log(tomorrow);  
console.log(today);

此时,两个时间输出是一样的,不符合我们的预期。正因为 Date() 对象存在的种种问题。平时我们经常需要借助 moment.js、Day.js等日期库,但是它们的体积较大,有时一个简单的日期处理就需要引入一个库,得不偿失。

目前,由于Date API 在很多库和浏览器引擎中的广泛使用,没有办法修复API的不好的部分。而改变Date API 的工作方式也很可能会破坏许多网站和库。

正因如此,TC39提出了一个全新的用于处理日期和时间的标准对象和函数——Temporal。新的Temporal API 提案旨在解决Date API的问题。它为 JavaScript 日期/时间操作带来了以下修复:

  • 仅可以创建和处理不可变Temporal对象;
  • 提供用于日期和时间计算的简单 API;
  • 支持所有时区;
  • 从 ISO-8601 格式进行严格的日期解析;
  • 支持非公历。

Temporal 将取代 Moment.js 之类的库,这些库很好地填补了 JavaScript 中的空白,这种空白非常普遍,因此将功能作为语言的一部分更有意义。

由于该提案还未正式发布,所以,可以借助官方提供的prlyfill来测试。首选进行安装:

javascript

复制代码

npm install @js-temporal/polyfill

导入并使用:

javascript

复制代码

import { Temporal } from'@js-temporal/polyfill';

console.log(Temporal);

Temporal 对象如下:10.webp.jpg下面就来看看 Temporal 对象有哪些实用的功能。11.webp.jpg

当前时间和日期

Temporal.Now 会返回一个表示当前日期和时间的对象:

javascript

复制代码

// 自1970年1月1日以来的时间(秒和毫秒)
Temporal.Now.instant().epochSeconds;
Temporal.Now.instant().epochMilliseconds;
// 当前位置的时间
Temporal.Now.zonedDateTimeISO();
// 当前时区
Temporal.Now.timeZone();
// 指定时区的当前时间
Temporal.Now.zonedDateTimeISO('Europe/London');

实例时间和日期

Temporal.Instant 根据 ISO 8601 格式的字符串返回一个表示日期和时间的对象,结果会精确到纳秒:

javascript

复制代码

Temporal.Instant.from('2022-02-01T05:56:78.999999999+02:00[Europe/Berlin]');
// 输出结果:2022-02-01T03:57:18.999999999Z 
Temporal.Instant.from('2022-02-011T05:06+07:00');
// 输出结果:2022-01-31T22:06:00Z

除此之外,还可以获取纪元时间的对应的日期(UTC 1970年1月1日0点是纪元时间):

javascript

复制代码

Temporal.Instant.fromEpochSeconds(1.0e8);
// 输出结果:1973-03-03T09:46:40Z

时区日期和时间

Temporal.ZonedDateTime 返回一个对象,该对象表示在特定时区的日期/时间:

javascript

复制代码

new Temporal.ZonedDateTime(
  1234567890000, // 纪元时间
  Temporal.TimeZone.from('Europe/London'), // 时区
  Temporal.Calendar.from('iso8601') // 默认日历
);
Temporal.ZonedDateTime.from('2025-09-05T02:55:00+02:00[Africa/Cairo]');
Temporal.Instant('2022-08-05T20:06:13+05:45').toZonedDateTime('+05:45');
// 输出结果:
Temporal.ZonedDateTime.from({
  timeZone: 'America/New_York',
  year: 2025,
  month: 2,
  day: 28,
  hour: 10,
  minute: 15,
  second: 0,
  millisecond: 0,
  microsecond: 0,
  nanosecond: 0
});
// 输出结果:2025-02-28T10:15:00-05:00[America/New_York]

简单的日期和时间

我们并不会总是需要使用精确的时间,因此 Temporal API 提供了独立于时区的对象。这些可以用于更简单的活动。

  • Temporal.PlainDateTime:指日历日期和时间;
  • Temporal.PlainDate:指特定的日历日期;
  • Temporal.PlainTime:指一天中的特定时间;
  • Temporal.PlainYearMonth:指没有日期成分的日期,例如“2022 年 2 月”;
  • Temporal.PlainMonthDay:指没有年份的日期,例如“10 月 1 日”。

它们都有类似的构造函数,以下有两种形式来创建简单的时间和日期:

javascript

复制代码

new Temporal.PlainDateTime(2021, 5, 4, 13, 14, 15);
Temporal.PlainDateTime.from('2021-05-04T13:14:15');
new Temporal.PlainDate(2021, 5, 4);
Temporal.PlainDate.from('2021-05-04');
new Temporal.PlainTime(13, 14, 15);
Temporal.PlainTime.from('13:14:15');
new Temporal.PlainYearMonth(2021, 4);
Temporal.PlainYearMonth.from('2019-04');
new Temporal.PlainMonthDay(3, 14);
Temporal.PlainMonthDay.from('03-14');

日期和时间值

所有 Temporal 对象都可以返回特定的日期/时间值。例如,使用ZonedDateTime

javascript

复制代码

c
onst t1 = Temporal.ZonedDateTime.from('2025-12-07T03:24:30+02:00[Africa/Cairo]');
t1.year;        // 2025
t1.month;       // 12
t1.day;         // 7
t1.hour;        // 3
t1.minute;      // 24
t1.second;      // 30
t1.millisecond; // 0
t1.microsecond; // 0
t1.nanosecond;  // 0

其他有用的属性包括:

  • dayOfWeek(周一为 1 至周日为 7)
  • dayOfYear(1 至 365 或 366)
  • weekOfYear(1 到 52,有时是 53)
  • daysInMonth(28、29、30、31)
  • daysInYear(365 或 366)
  • inLeapYear(true或false)

比较和排序日期

所有 Temporal 对象都可以使用 compare() 返回整数的函数进行比较。例如,比较两个ZonedDateTime对象:

javascript

复制代码

Temporal.ZonedDateTime.compare(t1, t2);

这个比较结果会有三种情况:

  • 当两个时间值相等时,返回 0;
  • 当 t1 在 t2 之后时,返回 1;
  • 当 t1 在 t2 之前时,但会 -1;

javascript

复制代码

const date1 = Temporal.Now,
const date2 = Temporal.PlainDateTime.from('2022-05-01');

Temporal.ZonedDateTime.compare(date1, date2); // -1

compare() 的结果可以用于数组的 sort() 方法来对时间按照升序进行排列(从早到晚):

javascript

复制代码

const t = [
  '2022-01-01T00:00:00+00:00[Europe/London]',
  '2022-01-01T00:00:00+00:00[Africa/Cairo]',
  '2022-01-01T00:00:00+00:00[America/New_York]'
].map(d => Temporal.ZonedDateTime.from(d))
  .sort(Temporal.ZonedDateTime.compare);

日期计算

提案还提供了几种方法来对任何 Temporal 对象执行日期计算。当传递一个Temporal.Duration对象时,它们都会返回一个相同类型的新的 Temporal,该对象使用years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds 和 nanoseconds 字段来设置时间。

javascript

复制代码

const t1 = Temporal.ZonedDateTime.from('2022-01-01T00:00:00+00:00[Europe/London]');

t1.add({ hours: 8, minutes: 30 }); // 往后8小时30分t1.subtract({ days: 5 });  // 往前5天t1.round({ smallestUnit: 'month' });  // 四舍五入到最近的月份

until() 和 since() 方法会返回一个对象,该 Temporal.Duration 对象描述基于当前日期/时间的特定日期和时间之前或之后的时间,例如:

javascript

复制代码

t1.until().months; // 到t1还有几个月t2.until().days;  // 到t2还有几天t3.since().weeks; // t3已经过去了几周

equals() 方法用来确定两个日期/时间值是否相同:

javascript

复制代码

const d1 = Temporal.PlainDate.from('2022-01-31');
const d2 = Temporal.PlainDate.from('2023-01-31');
d1.equals(d2);  // false

格式化日期

虽然这不是 Temporal API 的一部分,但 JavaScript Intl(国际化)API提供了一个 DateTimeFormat() 构造函数,可以用于格式化 Temporal 或 Date 对象:

javascript

复制代码

const d = new Temporal.PlainDate(2022, 3, 14);
// 美国日期格式:3/14/2022
new Intl.DateTimeFormat('en-US').format(d);
// 英国日期格式:14/3/2022
new Intl.DateTimeFormat('en-GB').format(d);
// 西班牙长日期格式:miércoles, 14 de abril de 2022
new Intl.DateTimeFormat('es-ES', { dateStyle: 'full' }).format(d);

浏览器支持

目前还没有浏览器支持 Temporal API:13.webp.jpgTemporal 提案tc39.es/proposal-te…

日期/时间操作库

在 JavaScript 中进行日期/时间操作是一个很麻烦的事,JS的生态中有很多实用的日期操作库,最后就来分享几个实用的日期库。

Moment.js

Moment.js 是一个轻量级 JavaScript 日期库,用于解析、验证、操作和格式化日期,是一个很受欢迎的日期操作库。

不过,Moment.js 是一个遗留项目,现在处于维护模式。维护者认为,无法重构 **Moment.js **来满足现代 JavaScript 开发的需求,例如不变性和 tree shaking。Lighthouse(Chrome 的内置审核工具)警告不要使用 Moment,因为它的大小较大 (329 kb)。

安装Moment.js

可以通过以下任一方式来安装该库:

shell

复制代码

npm install moment --save   # npm
yarn add moment             # Yarn
Install-Package Moment.js   # NuGet
spm install moment --save   # spm
meteor add momentjs:moment  # meteor

导入Moment.js

在 JavaScript 文件中,导入Moment.js库:

javascript

复制代码

const moment = require('moment');

创建日期对象

可以传递一个日期字符串或日期对象给moment()函数,然后返回一个Moment对象:

javascript

复制代码

const date = moment('2023-07-04');

格式化日期显示

Moment.js 提供了丰富的日期格式化选项。可以使用format()方法将日期格式化为所需的字符串格式:

javascript

复制代码

const formattedDate = date.format('YYYY-MM-DD');
console.log(formattedDate); // 输出:2023-07-04

日期运算

Moment.js提供了许多方便的方法来进行日期和时间的运算。下面是一些示例:

javascript

复制代码

// 添加一天
const tomorrow = date.add(1, 'day');
console.log(tomorrow.format('YYYY-MM-DD')); // 输出:2023-07-05
// 减去一个月
const lastMonth = date.subtract(1, 'month');
console.log(lastMonth.format('YYYY-MM-DD')); // 输出:2023-06-04
// 比较日期
const otherDate = moment('2023-07-10');
console.log(date.isBefore(otherDate)); // 输出:true
console.log(date.isAfter(otherDate)); // 输出:false

Moment.js还提供了许多其他常用的功能,如获取当前日期、解析日期字符串、计算日期之间的差异等。

Date-fns

Date-fns 是一个现代、轻量级的JavaScript日期处理库,用于在浏览器和Node.js环境中处理日期和时间。它的设计目标是提供一组简单、纯函数式的API来执行各种日期操作,而不依赖于全局对象。

以下是Date-fns 的特点:

  1. 轻量级:Date-fns非常小巧,只包含所需的功能,可以减少项目的文件大小。
  2. 纯函数:Date-fns的函数都是纯函数,即相同的输入总是产生相同的输出,不存在副作用。这使得代码更可预测、易测试和可维护。
  3. 易于使用:Date-fns的API设计简单易懂,与现代JavaScript的语法和惯用法保持一致。它提供了大量的日期处理功能,如格式化、解析、比较、计算等。
  4. 兼容性:Date-fns支持所有现代的浏览器和Node.js版本。

安装Date-fns

可以使用npm或yarn等包管理工具来安装Date-fns。在项目目录下运行以下命令安装Date-fns:

javascript

复制代码

npm install date-fns

导入Date-fns

在JavaScript文件中导入所需的Date-fns函数:

javascript

复制代码

import { format, parseISO, differenceInDays } from'date-fns';

使用Date-fns函数

使用导入的函数来执行各种日期操作。以下是一些示例:

const date = new Date();
// 格式化日期
const formattedDate = format(date, 'yyyy-MM-dd');
console.log(formattedDate); // 输出:2023-07-04
// 解析日期字符串
const parsedDate = parseISO('2023-07-04');
console.log(parsedDate); // 输出:Tue Jul 04 2023 00:00:00 GMT+0530 (India Standard Time)
// 计算日期之间的差异
const startDate = new Date(2023, 6, 1);
const endDate = new Date(2023, 6, 10);
const diff = differenceInDays(endDate, startDate);
console.log(diff); // 输出:9

在上述示例中,使用了format()函数将日期格式化为指定的字符串格式,使用了parseISO()函数解析日期字符串为日期对象,以及使用了differenceInDays()函数计算两个日期之间的天数差异。

Day.js

Day.js 是一个轻量级的JavaScript日期处理库,用于解析、操作和格式化日期对象。它的设计目标是提供一个简单、灵活的API,使得处理日期和时间变得更加方便。

以下是 Day.js 的特点:

  1. 轻量级:Day.js非常小巧,压缩后仅有2 KB左右的大小,可以减少项目的文件大小。
  2. 易用性:Day.js的API设计简洁明了,与现代JavaScript的语法和惯用法保持一致。你可以轻松地对日期进行解析、格式化、计算、比较等操作。
  3. 不可变性:Day.js的日期对象是不可变的,即每次对日期进行操作都会返回一个新的日期对象,而不会修改原始对象。这种设计模式有助于避免副作用,并提高代码的可预测性。
  4. Moment.js兼容性:Day.js的API设计与Moment.js类似,因此可以很容易地从Moment.js迁移到Day.js,而无需更改太多代码。

安装Day.js

可以使用npm或yarn等包管理工具来安装Day.js。在项目目录下运行以下命令安装Day.js:

javascript

复制代码

npm install dayjs

导入Day.js

在JavaScript文件中导入Day.js:

javascript

复制代码

import dayjs from'dayjs';

使用Day.js函数

使用Day.js的函数来进行日期操作。以下是一些示例:


const date = dayjs();
// 格式化日期
const formattedDate = date.format('YYYY-MM-DD');
console.log(formattedDate); // 输出:2023-07-04
// 解析日期字符串
const parsedDate = dayjs('2023-07-04');
console.log(parsedDate); // 输出:Tue Jul 04 2023 00:00:00 GMT+0530 (India Standard Time)
// 计算日期之间的差异
const startDate = dayjs('2023-07-01');
const endDate = dayjs('2023-07-10');
const diff = endDate.diff(startDate, 'day');
console.log(diff); // 输出:9

在上述示例中,使用了format()函数将日期格式化为指定的字符串格式,使用了dayjs()函数解析日期字符串为日期对象,以及使用了diff()函数计算两个日期之间的天数差异。

Luxon

Luxon 是一个用于处理日期、时间和时区的先进 JavaScript 库。它提供了一组强大的功能,可以帮助你在浏览器和 Node.js 环境中轻松处理日期和时间。

以下是 Luxon 的特点:

  1. 强大的日期和时间处理:Luxon 提供了丰富的 API,用于解析、格式化、操作和比较日期和时间。它支持多种标准和自定义的日期和时间格式,包括 ISO 8601、RFC 2822 等。
  2. 支持时区处理:Luxon 支持全球各地的时区,并提供了灵活的时区转换功能。它使用 IANA(Olson)时区数据库,确保准确的时区信息。
  3. 不可变性:Luxon 的日期对象是不可变的,每次对日期进行操作都会返回一个新的日期对象,而不会修改原始对象。这种设计模式有助于避免副作用,并提高代码的可预测性。
  4. 链式调用:Luxon 的 API 允许你使用链式调用,使得代码更简洁、易读。你可以按顺序执行多个操作,而无需多次引用日期对象。

安装 Luxon

使用 npm 或 yarn 等包管理工具,在项目目录下运行以下命令安装 Luxon:

javascript

复制代码

npm install luxon

导入 Luxon

在 JavaScript 文件中导入 Luxon:

javascript

复制代码

import { DateTime } from'luxon';

使用 Luxon 函数

使用 Luxon 的函数来处理日期和时间。以下是一些示例:

const now = DateTime.now();
// 格式化日期
const formattedDate = now.toFormat('yyyy-MM-dd');
console.log(formattedDate); // 输出:2023-07-04
// 解析日期字符串
const parsedDate = DateTime.fromISO('2023-07-04');
console.log(parsedDate); // 输出:DateTime { ... }
// 计算日期之间的差异
const startDate = DateTime.fromISO('2023-07-01');
const endDate = DateTime.fromISO('2023-07-10');
const diff = endDate.diff(startDate, 'days').toObject().days;
console.log(diff); // 输出:9

在上述示例中,使用了 toFormat() 函数将日期格式化为指定的字符串格式,使用了 fromISO() 函数解析 ISO 8601 格式的日期字符串为日期对象,以及使用了 diff() 函数计算两个日期之间的天数差异。

相关文章
|
2月前
|
JavaScript 前端开发
JavaScript Date(日期) 对象
JavaScript Date(日期) 对象
42 2
|
3月前
|
JavaScript 前端开发
js时间戳转日期时间
js时间戳转日期时间
85 20
|
28天前
|
JavaScript 前端开发 搜索推荐
Moment.js、Day.js、Miment,日期时间库怎么选?
【10月更文挑战第29天】如果你需要一个功能强大、插件丰富的日期时间库,并且对性能要求不是特别苛刻,Moment.js是一个不错的选择;如果你追求极致的轻量级和高性能,那么Day.js可能更适合你;而如果你有一些特定的日期时间处理需求,并且希望在性能和功能之间取得平衡,Miment也是可以考虑的。
|
3月前
|
JavaScript 前端开发
|
6月前
|
JavaScript vr&ar 数据库
技术笔记:Js获取当前日期时间及其它操作
技术笔记:Js获取当前日期时间及其它操作
139 1
|
5月前
|
JavaScript
vue 农历日期转公历日期(含插件 js-calendar-converter 使用教程)
vue 农历日期转公历日期(含插件 js-calendar-converter 使用教程)
241 0
|
5月前
|
JavaScript 前端开发
js/javascript 操作时间日期【全】含时间日期的创建、获取、比较、计算、格式化、时间戳、昨天、今天、星期汉化、计时、相关插件等
js/javascript 操作时间日期【全】含时间日期的创建、获取、比较、计算、格式化、时间戳、昨天、今天、星期汉化、计时、相关插件等
111 0
|
6月前
|
JavaScript vr&ar 数据库
一篇文章讲明白JS获取当前日期
一篇文章讲明白JS获取当前日期
195 0
|
7月前
|
JavaScript 前端开发 Shell
JS获取当前时间、及一周之前、一个月之前日期
这段代码展示了JavaScript中获取当前时间以及过去特定日期的方法。包括获取时间戳和格式化日期的函数,例如获取一周、一个月前的日期。另外,还包含了添加随机数的日期时间戳生成和计算两个日期之间差值的示例。
|
7月前
|
JavaScript 前端开发
js对比日期大小
js对比日期大小
43 1