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

简介: 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
JS设置日期为0时0分0秒
项目中经常要给设置默认值,搜索从哪天开始,这时候,如果直接通过new Date()来获取时间,会有时分秒,如果快速设置为0时0分0秒?
30 0
|
3月前
|
移动开发 JavaScript 前端开发
分享76个时间日期JS特效,总有一款适合您
分享76个时间日期JS特效,总有一款适合您
33 0
|
4月前
|
JavaScript 前端开发
javascript 如何判断字符串日期是否相差七天
在JavaScript中,你可以使用`Date`对象来比较两个日期之间的差异。下面是一个简单的示例,演示如何判断两个字符串日期是否相差七天: ```javascript function isSevenDaysDifference(date1, date2) { // 确保输入是字符串 if (typeof date1 !== 'string' || typeof date2 !== 'string') { return false; } // 将字符串转换为Date对象 var d1 = new Date(date1);
|
4月前
|
存储 前端开发 JavaScript
实现一个简单的JavaScript日期选择器
实现一个简单的JavaScript日期选择器
|
3月前
|
JavaScript 前端开发 UED
分享89个时间日期JS特效,总有一款适合您
分享89个时间日期JS特效,总有一款适合您
32 3
|
1天前
|
JavaScript 前端开发
实现一个JavaScript动态日期功能
实现一个JavaScript动态日期功能
|
4月前
|
资源调度 JavaScript 前端开发
jc-datetime :JavaScript 日期时间实用编程
jc-datetime :JavaScript 日期时间实用编程
160 1
|
4月前
|
JavaScript 算法
JS中如何对<input type=“data“>中值进行运算(JS日期类型如何进行加减)
JS中如何对<input type=“data“>中值进行运算(JS日期类型如何进行加减)
26 0
|
4月前
|
JavaScript
js知识总结 -- Math对象、data日期对象的方法及功能
js知识总结 -- Math对象、data日期对象的方法及功能
17 0
|
4月前
|
JavaScript 前端开发 小程序
js两个日期比较相差多少天实例
js两个日期比较相差多少天实例