Skip to page content

时间工具

Quasar 提供了一组有用的函数,可以在大多数使用情况下轻松地操作 JS Date,而无需额外引入像 Momentjs 这样的专用库。

大多数 Quasar 时间函数的参数可以是一个 Unix 时间戳,也可以是一个能被原生 JS Date 构造函数解析的字符串。例如:1497159857411、Sun Jun 11 2017 08:44:42 GMT+0300、2017-06-16。

返回值都是 JS Date 对象。

熟悉 JS 原生 Date 类,它非常强大,请记住您不需要像 Momentjs 之类的方案,它们会给打包产物增加数百 KB 的体积。

TIP

除了 UMD 版本外,Quasar 的时间函数都支持 tree shaking。

下面所有的示例都从 Quasar 中导入了 date 对象。如果您只需要其中的一个方法,可以使用 ES6 解构来实现更好的 Tree Shaking,只保留需要的方法而不是整个 date。

以 addToDate() 为例:

// 导入整个 `date`
import { date } from "quasar";
// 解构出需要的方法
const { addToDate } = date;

const newDate = addToDate(new Date(), { days: 7, months: 1 });
TIP

有关 UMD 构建的用法,请参阅此处。

显示格式化日期

接受一个格式字符串,并将日期值替换为对应的格式标记:

import { date } from "quasar";

const timeStamp = Date.now();
const formattedString = date.formatDate(timeStamp, "YYYY-MM-DDTHH:mm:ss.SSSZ");

对于 i18n 场景,可以使用第三个参数:

const formattedString = date.formatDate(timeStamp, "MMMM - dddd", {
  days: ["Duminica", "Luni" /* 以及剩下的所有天,记得从周日开始 */],
  daysShort: ["Dum", "Lun" /* 以及剩下的所有天,记得从周日开始 */],
  months: ["Ianuarie", "Februarie" /* 以及剩下的所有月份 */],
  monthsShort: ["Ian", "Feb" /* 以及剩下的所有月份 */],
});

可用的格式标记:

单位可用的格式
Year
  • YY: 70 71 … 29 30
  • YYYY: 1970 1971 … 2029 2030
Month
  • M: 1 2 … 11 12
  • Mo: 1st 2nd … 11th 12th
  • MM: 01 02 … 11 12
  • MMM: Jan Feb … Nov Dec
  • MMMM: January February … November December
Quarter
  • Q: Quarter number 1 2 3 4
  • Qo: Quarter number 1st 2nd 3rd 4th
Day of Month
  • D: 1 2 … 30 31
  • Do: 1st 2nd … 30th 31st
  • DD: 01 02 … 30 31
Day of Year
  • DDD: 1 2 … 364 365
  • DDDo: 1st 2nd … 364th 365th
  • DDDD: 001 002 … 364 365
Day of Week
  • d: 0 1 … 5 6
  • do: 0th 1st … 5th 6th
  • dd: Su Mo … Fr Sa
  • ddd: Sun Mon … Fri Sat
  • dddd: Sunday Monday … Friday Saturday
Day of Week (ISO)
  • E: 1 2 … 6 7
Week of Year
  • w: 1 2 … 52 53
  • wo: 1st 2nd … 52nd 53rd
  • ww: 01 02 … 52 53
Hour
  • H: 0 1 … 22 23
  • HH: 00 01 … 22 23
  • h: 0 … 11 12
  • hh: 01 02 … 11 12
Minute
  • m: 0 1 … 58 59
  • mm: 00 01 … 58 59
Second
  • s: 0 1 … 58 59
  • ss: 00 01 … 58 59
Fractional Second
  • S: 0 1 … 8 9
  • SS: 00 01 … 98 99
  • SSS: 000 001 … 998 999
Timezone offset
  • Z: -07:00 -06:00 … +06:00 +07:00
  • ZZ: -0700 -0600 … +0600 +0700
AM/PM
  • A: AM, PM
  • a: am, pm
  • aa: a.m, p.m
Unix Timestamp
  • X: 1360013296
  • x (ms): 1360013296123

如果您希望在格式掩码中插入字符串(包括 [ 和 ] 字符),请确保用 [ 和 ] 包裹它们来转义,否则这些字符可能会被解析为格式标记。

操作日期

创建

建议使用原生 JS Date 类来创建日期,例如:

const date = new Date();

以下方法只是一个封装,用于帮助您创建基于当前时间但修改了年、月、秒等部分的日期。

import { date } from "quasar";

const newDate = date.buildDate({
  year: 2010,
  date: 5,
  hours: 15,
  milliseconds: 123,
});

可以传入第二个参数(布尔值)来设置使用 UTC 时间(true)而非本地时间。

传入的对象可以包含以下字段(均为可选):

字段描述
millisecond(s)日期/时间中的毫秒部分
second(s)日期/时间中的秒部分
minute(s)日期/时间中的分钟部分
hour(s)日期/时间中的小时部分
day(s) / date日期/时间中的天部分
month(s)日期/时间中的月部分
year(s)日期/时间中的年部分

验证

检查一个日期字符串是否合法:

import { date } from "quasar";

const dateString = "Wed, 09 Aug 1995 00:00:00 GMT";

if (date.isValid(dateString)) {
  // Do something with date string
}
WARNING

isValid 只验证日期格式,不验证日期的逻辑有效性。

其底层实现基于原生 Date.parse(...) API,该 API 的局限性也会透传到我们的 API 中。

它不会检查日期对于所在月份是否有效(例如 2 月 31 日),也不会检查日期对于所在年份是否有效(例如非闰年的 2 月 29 日),而且在这些情况下 Firefox 和基于 Chromium 的浏览器(Chrome、Edge 等)会返回不同的值。

加/减

对日期进行加/减一段时间:

import { date } from "quasar";

let newDate = new Date(2017, 2, 7);

newDate = date.addToDate(newDate, { days: 7, months: 1 });
// `newDate` 现在为 2017-3-14 00:00:00

newDate = date.subtractFromDate(newDate, { hours: 24, milliseconds: 10000 });
// `newDate` 现在为 2017-3-12 23:59:50

传入的对象可以包含以下字段(均为可选):

字段描述
millisecond(s)以毫秒为单位的时间段
second(s)以秒为单位的时间段
minute(s)以分钟为单位的时间段
hour(s)以小时为单位的时间段
day(s) / date以天为单位的时间段
month(s)以月为单位的时间段
year(s)以年为单位的时间段

设置日期/时间

设置日期/时间的指定部分:

import { date } from "quasar";

const newDate = new Date(2017, 10, 2);
const adjustedDate = date.adjustDate(newDate, { year: 2010, month: 2 });
// `adjustedDate` 变成 2010-2-2

可以传入第三个参数(布尔值)来设置使用 UTC 时间(true)而非本地时间。

传入的对象可以包含以下字段(均为可选):

字段描述
millisecond(s)日期/时间中的毫秒部分
second(s)日期/时间中的秒部分
minute(s)日期/时间中的分钟部分
hour(s)日期/时间中的小时部分
day(s) / date日期/时间中的天部分
month(s)日期/时间中的月部分
year(s)日期/时间中的年部分

查询日期

最大/最小值

从一组日期中获取最大/最小的日期:

import { date } from "quasar";

let min = date.getMinDate(new Date(2017, 6, 24), new Date(2017, 5, 20), new Date(2017, 6, 26));
// `min` 为 2017-5-20
let max = date.getMaxDate(new Date(2017, 6, 24), new Date(2017, 5, 20), new Date(2017, 6, 26));
// `max` 为 2017-6-26

// 或者使用数组:
const dates = [new Date(2017, 6, 24), new Date(2017, 5, 20), new Date(2017, 6, 26)];
let min = date.getMinDate(...dates); // `min` 为 2017-5-20
let max = date.getMaxDate(...dates); // `max` 为 2017-6-26

注意返回值是一个时间戳。

console.log(max); // 1497906000000
console.log(new Date(max)); // Wed Jul 26 2017 00:00:00 GMT+0300 (Eastern European Summer Time)

时间范围

查询日期是否在指定的日期/时间范围内:

import { date } from "quasar";

const dateTarget = new Date();
const dateFrom = new Date();
const dateTo = new Date();

// **严格**比较(即不包含边界)
if (date.isBetweenDates(dateTarget, dateFrom, dateTo)) {
  // Do something with dateTarget
}

// 包含指定的边界
if (
  date.isBetweenDates(dateTarget, dateFrom, dateTo, {
    inclusiveFrom: true,
    inclusiveTo: true,
  })
) {
  // Do something with dateTarget
}

// 如果只关心日期部分(年/月/日,忽略时间),
// 可以使用 onlyDate 提示 isBetweenDates() 以获得最佳性能:
if (date.isBetweenDates(dateTarget, dateFrom, dateTo, { onlyDate: true })) {
  // Do something with dateTarget
}

将日期规范化到指定的日期/时间范围内:

import { date } from "quasar";

const newDate = new Date();
const dateMin = new Date(2010, 2, 23);
const dateMax = new Date(2012, 4, 12);
const dateNormalized = date.getDateBetween(newDate, dateMin, dateMax);
// 如果 newDate 在 2010-2-23 和 2012-4-12 之间,则返回 newDate;
// 小于 dateMin 则返回 dateMin;大于 dateMax 则返回 dateMax

判断相等

判断两个日期的指定单位是否相等:

import { date } from "quasar";

const date1 = new Date(2017, 2, 5);
const date2 = new Date(2017, 3, 8);
const unit = "year";

if (date.isSameDate(date1, date2, /* 可选 */ unit)) {
  // true,因为 date1 和 date2 的年份相同
}

单位参数可以省略,此时将进行完整的日期/时间比较,否则执行部分比较:

单位描述
second(s)只比较秒是否相同
minute(s)只比较分钟是否相同
hour(s)只比较小时是否相同
day(s) / date只比较天是否相同
month(s)只比较月是否相同
year(s)只比较年是否相同

查询时间差

计算两个日期之间的时间差:

import { date } from "quasar";

const date1 = new Date(2017, 4, 12);
const date2 = new Date(2017, 3, 8);
const unit = "days";

const diff = date.getDateDiff(date1, date2, unit);
// `diff` 是 34(天)

单位参数表示计量单位,如果没有指定,则默认为 days:

单位描述
second(s)相差多少秒(忽略毫秒)
minute(s)相差多少分钟(忽略秒等)
hour(s)相差多少小时(忽略分钟、秒等)
day(s) / date相差多少个日历天
month(s)相差多少个日历月
year(s)相差多少个日历年

日历

获取给定日期的 ISO 标准年内周数:

import { date } from "quasar";

const newDate = new Date(2017, 0, 4);
const week = date.getWeekOfYear(newDate); // `week` 为 1

获取给定日期在一年中的第几天:

import { date } from "quasar";

const newDate = new Date(2017, 1, 4);
const day = date.getDayOfYear(newDate); // `day` 为 35

获取给定日期在一周中的第几天:

import { date } from "quasar";

const newDate = new Date(2017, 1, 9);
const day = date.getDayOfWeek(newDate); // `day` 为 4

获取指定日期所在月份的天数:

date.daysInMonth(date, utc) 返回包含指定日期的月份的天数,不会修改输入值。

可选的 utc 布尔参数默认为 false,即读取输入的本地年月。设为 true 则读取 UTC 年月。当输入代表的 UTC 日历值在转换为本地时间时可能落在不同月份时,这很有用。

import { date } from "quasar";

const leapYearDate = new Date('2024-02-15T12:00:00.000Z')

const localDays = date.daysInMonth(leapYearDate) // 29
const utcDays = date.daysInMonth(leapYearDate, true) // 29

日期的开始/结束

将日期设置为某个单位时间的开始或结束:

import { date } from "quasar";

let newDate = new Date("2000");
// 设置为 2000 年的开始时间(January 1st, 2000, 00:00:00.000)
newDate = date.startOfDate(newDate, "year");
// 设置为 2000 年的结束时间(December 31st, 2000, 23:59:59.999)
newDate = date.endOfDate(newDate, "year");

第二个参数表示要重置的单位(它的开始或结束):

单位描述
second(s)重置秒
minute(s)重置分钟
hour(s)重置小时
day(s) / date重置天
month(s)重置月
year(s)重置年

其他

获取格式

import { date } from "quasar";

date.inferDateFormat(new Date()); // 'date'
date.inferDateFormat(35346363); // 'number'
date.inferDateFormat("Mon Feb 05 2018 23:05:29"); // string

克隆日期

import { date } from "quasar";

const newDate = new Date();
const clonedDate = date.clone(newDate);

date.addToDate(newDate, { days: 1 });

console.log(newDate.getDate() === clonedDate.getDate()); // false

提取日期

利用当前 Quasar 语言包的语言环境设置,可以根据传入的格式将任何字符串解析为日期对象:

import { date } from "quasar";

// 示例 1
const date = date.extractDate("2019-10-29 --- 23:12", "YYYY-MM-DD --- HH:mm");
// date 是一个新的 Date() 对象

// 示例 2
const date = date.extractDate("21/03/1985", "DD/MM/YYYY");
// date 是一个新的 Date() 对象

输入可以在掩码描述的部分之后包含额外文本。当输入不是以匹配的值开头,或包含不可能的日期、时间或时区组件时,extractDate() 返回一个 Invalid Date 对象:

const parsed = date.extractDate('2024-02-30', 'YYYY-MM-DD')
console.log(Number.isNaN(parsed.getTime())) // true

解析 ISO 周日期
v2.30+

带有周数标记(w、wo 或 ww)的掩码会被按 ISO 周日期解析,因此 formatDate() 的输出可以往返解析回同一天:

import { date } from 'quasar'

date.extractDate('2020-W40-7', 'GGGG-[W]ww-E')
// 2020 年 10 月 4 日,星期日

当掩码含有 GG/GGGG 时,年份取自它,否则取自 YY/YYYY。请优先使用 ISO 周年标记:在元旦前后的那几天里,日历年份与 ISO 周年份并不相同,此时把 YYYY 和 ww 搭配使用会解析到错误周里的某一天。

星期几取自掩码中所含的 E、d、do、dd、ddd 或 dddd 中的任意一个。不含星期几的掩码会解析为该周开始的星期一,因为 ISO 周从星期一开始:

date.extractDate('2020-40', 'YYYY-ww')
// 2020 年 9 月 28 日,星期一

周数始终按 ISO 8601 解释(周从星期一开始,第 1 周是包含 1 月 4 日的那一周),与 formatDate() 写出的以及 getWeekOfYear() 返回的一致。所用的语言包不会改变它,QDate 的 first-day-of-week 属性也不会——后者只影响日历的显示方式。

不存在的周会得到一个 Invalid Date(无效日期),包括某年只有 52 周时的第 53 周:

const parsed = date.extractDate('2021-W53', 'GGGG-[W]ww')
console.log(Number.isNaN(parsed.getTime())) // true

当一个掩码同时含有周数和完整的日历日期时,以日历日期为准:

date.extractDate('2021-W52 2022-01-01', 'GGGG-[W]ww YYYY-MM-DD')
// 2022 年 1 月 1 日
WARNING

dd 标记会把星期名缩短为其前两个字符,这在有些语言里并不唯一(中文会把七天全都缩写成相同的两个字符)。在当前语言包出现这种歧义的场合,dd 会被匹配但被忽略,日期解析为该周的星期一。请改用 ddd、dddd 或 E 来获得在任何语言下都能正确解析的星期几。

使用自定义语言环境:

自定义的日期和月份名称会按字面量匹配,包括它们可能包含的任何正则表达式元字符。

import { date } from "quasar";

const obj = date.extractDate(
  "Month: Feb, Day: 11th, Year: 2018",
  "[Month: ]MMM[, Day: ]Do[, Year: ]YYYY",
  {
    days: ["Duminica", "Luni" /* 以及剩下的所有天,记得从周日开始 */],
    daysShort: ["Dum", "Lun" /* 以及剩下的所有天,记得从周日开始 */],
    months: ["Ianuarie", "Februarie" /* 以及剩下的所有月份 */],
    monthsShort: ["Ian", "Feb" /* 以及剩下的所有月份 */],
  },
);
// obj 是一个新的 Date() 对象