date-manip
Version:
A lightweight JavaScript date utility library that provides modularity, high performance, and additional features. It supports various date operations, including date addition and subtraction, formatting, comparison, etc.
276 lines (275 loc) • 7.35 kB
JavaScript
;
const compile = require("./compile.js");
const normalizeUnit = require("./normalizeUnit-Cn0hUyBC.js");
const units = require("./units.js");
const BASIC_ISO_REGEX = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
const EXTENDED_ISO_REGEX = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
const ISO_TIMES_REGEX = [
/(\d\d):(\d\d):(\d\d)\.(\d+)/,
// 'HH:mm:ss.SSSS'
/(\d\d):(\d\d):(\d\d),(\d+)/,
// 'HH:mm:ss,SSSS'
/(\d\d):(\d\d):(\d\d)/,
// 'HH:mm:ss'
/(\d\d):(\d\d)/,
// 'HH:mm'
/(\d\d)(\d\d)(\d\d)\.(\d+)/,
// 'HHmmss.SSSS'
/(\d\d)(\d\d)(\d\d),(\d+)/,
// 'HHmmss,SSSS'
/(\d\d)(\d\d)(\d\d)/,
// 'HHmmss'
/(\d\d)(\d\d)/,
// 'HHmm'
/(\d\d)/
// 'HH'
];
const TZ_REGEX = /(Z)|([+-]\d\d)(?::?(\d\d))?/;
const ISO_DATES_REGEX = [
/(\d{4})-(\d\d)-(\d\d)/,
// 'YYYY-MM-DD'
/(\d{4})-(\d\d)/,
// 'YYYY-MM'
/(\d{4})(\d\d)(\d\d)/,
// 'YYYYMMDD'
/(\d{4})(\d\d)/,
// 'YYYYMM'
/(\d{4})/
// 'YYYY'
];
function autoExtract(input) {
const dateRet = new Array(8);
let matches;
const match = EXTENDED_ISO_REGEX.exec(input) || BASIC_ISO_REGEX.exec(input);
if (match) {
const datesLen = ISO_DATES_REGEX.length;
for (let i = 0; i < datesLen; i++) {
if (matches = ISO_DATES_REGEX[i].exec(match[1])) {
for (let j = 0; j < 3; j++) {
const matched = matches[j + 1];
dateRet[j] = matched ? +matched : 1;
}
if (dateRet[1]) {
dateRet[1] -= 1;
}
break;
}
}
matches = null;
if (match[3]) {
for (let i = 0, timesLen = ISO_TIMES_REGEX.length; i < timesLen; i++) {
if (matches = ISO_TIMES_REGEX[i].exec(match[3])) {
if (matches[4]) {
matches[4] = matches[4].padEnd(3, "00");
}
for (let j = 1, len = matches.length; j < len; j++) {
dateRet[j + 2] = +matches[j];
}
break;
}
}
}
matches = null;
if (match[4]) {
matches = TZ_REGEX.exec(match[4]);
if (matches) {
dateRet[7] = matches[1] ? NaN : +matches[2] * 60 + (matches[3] ? +matches[3] : 0);
}
}
return dateRet;
}
return input;
}
function createDate(y, m, d, h, minute, s, ms) {
let date;
if (y < 100 && y >= 0) {
date = new Date(y + 400, m, d, h, minute, s, ms);
if (isFinite(date.getFullYear())) {
date.setFullYear(y);
}
} else {
date = new Date(y, m, d, h, minute, s, ms);
}
return date;
}
function createUTCDate(y, m, d, h, minute, s, ms) {
let date;
if (y < 100 && y >= 0) {
y += 400;
date = new Date(Date.UTC(y, m, d, h, minute, s, ms));
if (isFinite(date.getUTCFullYear())) {
date.setUTCFullYear(y);
}
} else {
date = new Date(Date.UTC(y, m, d, h, minute, s, ms));
}
return date;
}
function createFromArray(input) {
const utcOffset = input[7];
const currentDate = /* @__PURE__ */ new Date();
const isUTC = Number.isNaN(utcOffset);
const flag = isUTC ? "UTC" : "";
const currentStuffing = [
currentDate[`get${flag}FullYear`](),
currentDate[`get${flag}Month`](),
currentDate[`get${flag}Date`]()
];
let i = 0;
const array = new Array(7);
for (; i < 3 && input[i] == null; ++i) {
array[i] = currentStuffing[i];
}
for (; i < 7; i++) {
array[i] = input[i] == null ? 0 : input[i];
}
let day = array[2];
if (day === 0) {
day = 1;
}
let minute = array[4];
if (!isUTC && typeof utcOffset === "number") {
minute -= utcOffset + currentDate.getTimezoneOffset();
}
return (isUTC ? createUTCDate : createDate)(
array[0],
array[1],
day,
array[3],
minute,
array[5],
array[6]
);
}
function toInteger(val) {
return parseInt(val, 10);
}
function toMonth(val) {
return parseInt(val, 10) - 1;
}
function toMilliseconds(val) {
return parseInt(val.padEnd(3, "0"), 10);
}
function parseTimezone(val) {
if (val === "Z") {
return NaN;
}
const matches = TZ_REGEX.exec(val);
return +matches[2] * 60 + (matches[3] ? +matches[3] : 0);
}
function extractWithFormat(input, format) {
const { pattern, tokens } = compile(format);
const match = new RegExp(pattern).exec(input);
if (!match) {
return "";
}
const parts = [];
tokens.forEach((token, i) => {
const value = match[i + 1];
switch (token) {
case "YYYY":
parts[0] = toInteger(value);
break;
// case 'YY':
// parts[0] = toInteger(value);
// break;
case "MM":
parts[1] = toMonth(value);
break;
case "DD":
parts[2] = toInteger(value);
break;
case "HH":
parts[3] = toInteger(value);
break;
case "mm":
parts[4] = toInteger(value);
break;
case "ss":
parts[5] = toInteger(value);
break;
case "SSS":
parts[6] = toMilliseconds(value);
break;
case "Z":
parts[7] = parseTimezone(value);
break;
}
});
return parts;
}
const { DATE, DAY, HOUR, MILLISECOND, MINUTE, MONTH, SECOND, YEAR, UTC_OFFSET } = units;
const ASP_NET_JSON_REGEX = /^\/?Date\((-?\d+)/i;
function ensureType(value, checked) {
return checked;
}
function parseObject(obj) {
const array = [];
Object.entries(obj).forEach(([unit, value]) => {
unit = normalizeUnit.normalizeUnit(unit);
switch (unit) {
case YEAR:
array[0] = value;
break;
case MONTH:
array[1] = value;
break;
case DATE:
case DAY:
array[2] = value;
break;
case HOUR:
array[3] = value;
break;
case MINUTE:
array[4] = value;
break;
case SECOND:
array[5] = value;
break;
case MILLISECOND:
array[6] = value;
break;
case UTC_OFFSET:
array[7] = value;
break;
}
});
if (array.length === 0) {
return /* @__PURE__ */ new Date();
}
return createFromArray(array);
}
function parseString(input, format) {
const extracted = typeof format === "string" && format ? extractWithFormat(input, format) : autoExtract(input);
if (Array.isArray(extracted)) {
return createFromArray(extracted);
}
const matched = ASP_NET_JSON_REGEX.exec(input);
return new Date(matched !== null ? +matched[1] : Date.parse(extracted));
}
function parse(input, format) {
let ret;
const whatType = typeof input;
if (ensureType(input, whatType === "string")) {
ret = parseString(input, format);
} else if (Array.isArray(input)) {
ret = createFromArray(input);
} else if (input instanceof Date) {
ret = new Date(input);
} else if (ensureType(input, whatType === "object" && input !== null)) {
if (input.isValid && input.isValid()) {
ret = /* @__PURE__ */ new Date(+input);
} else {
ret = parseObject(input);
}
} else if (ensureType(input, whatType === "number")) {
ret = new Date(input);
} else if (ensureType(input, whatType === "undefined")) {
ret = format ? /* @__PURE__ */ new Date(NaN) : /* @__PURE__ */ new Date();
} else {
ret = new Date(Date.parse(input));
}
return ret;
}
module.exports = parse;