@sgx4u/date-time-utils
Version:
A date-time utility library
557 lines (544 loc) • 20.5 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
addSubtractTime: () => addSubtractTime,
dateTimeDifference: () => dateTimeDifference,
formatDateTime: () => formatDateTime,
getNextOccurrence: () => getNextOccurrence,
indexToDay: () => indexToDay,
indexToMonth: () => indexToMonth,
isLeapYear: () => isLeapYear,
isValidDate: () => isValidDate
});
module.exports = __toCommonJS(src_exports);
// src/utils/number.utils.ts
var padNumber = (value, size = 2) => {
return value.toString().padStart(size, "0");
};
// src/utils/date.utils.ts
var getValueFromDate = ({
date,
method,
useUTC
}) => {
const localOrUtc = useUTC ? `getUTC${method}` : `get${method}`;
return date[localOrUtc]();
};
// src/data/date.data.ts
var daysShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
var daysFull = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var monthsShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var monthsFull = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
];
// src/format-date-time/format-date-time.ts
var formatDateTime = (props = {}) => {
const { date, format = "HH:mm:ss | dd/MM/yyyy", useUTC = false } = props;
const thisDate = !("date" in props) ? /* @__PURE__ */ new Date() : date instanceof Date ? date : new Date(date);
if (isNaN(thisDate.getTime())) return "Invalid Date";
const getValue = (method) => {
return getValueFromDate({ date: thisDate, method, useUTC });
};
const getStringValue = (value) => value.toString();
const formattedValueCache = {};
const getFormattedValue = (type) => {
if (formattedValueCache[type] !== void 0) return formattedValueCache[type];
let value = "";
switch (type) {
// Hour 12h (1-12)
case "h":
value = getStringValue(
getValue("Hours") > 12 ? getValue("Hours") - 12 : getValue("Hours") === 0 ? 12 : getValue("Hours")
);
break;
// Hour 12h with leading 0 (01-12)
case "hh":
value = padNumber(
getValue("Hours") > 12 ? getValue("Hours") - 12 : getValue("Hours") === 0 ? 12 : getValue("Hours")
);
break;
// Hour 24h (0-23)
case "H":
value = getStringValue(getValue("Hours"));
break;
// Hour 24h with leading 0 (00-23)
case "HH":
value = padNumber(getValue("Hours"));
break;
// Minute (0-59)
case "m":
value = getStringValue(getValue("Minutes"));
break;
// Minute with leading 0 (00-59)
case "mm":
value = padNumber(getValue("Minutes"));
break;
// Second (0-59)
case "s":
value = getStringValue(getValue("Seconds"));
break;
// Second with leading 0 (00-59)
case "ss":
value = padNumber(getValue("Seconds"));
break;
// Millisecond (0-999)
case "S":
value = getStringValue(getValue("Milliseconds"));
break;
// Millisecond with 2 digits minimum (00-999)
case "SS":
value = padNumber(getValue("Milliseconds"), 2);
break;
// Millisecond with 3 digits minimum (000-999)
case "SSS":
value = padNumber(getValue("Milliseconds"), 3);
break;
// Day short (Sun-Sat)
case "EEE":
value = daysShort[getValue("Day")];
break;
// Day full (Sunday-Saturday)
case "EEEE":
value = daysFull[getValue("Day")];
break;
// Date (1-31)
case "d":
value = getStringValue(getValue("Date"));
break;
// Date with leading 0 (01-31)
case "dd":
value = padNumber(getValue("Date"));
break;
// Month (1-12)
case "M":
value = getStringValue(getValue("Month") + 1);
break;
// Month with leading 0 (01-12)
case "MM":
value = padNumber(getValue("Month") + 1);
break;
// Month short (Jan-Dec)
case "MMM":
value = monthsShort[getValue("Month")];
break;
// Month full (January-December)
case "MMMM":
value = monthsFull[getValue("Month")];
break;
// Year short (00-99)
case "yy":
value = getValue("FullYear").toString().slice(-2);
break;
// Year full (0000-9999)
case "yyyy":
value = getValue("FullYear").toString();
break;
// AM/PM
case "aa":
value = getValue("Hours") >= 12 ? "PM" : "AM";
break;
// full
case "full":
value = thisDate.toString();
break;
// UTC
case "UTC":
value = thisDate.toUTCString();
break;
// ISO
case "ISO":
value = thisDate.toISOString();
break;
// dateString
case "dateString":
value = thisDate.toDateString();
break;
// timeString
case "timeString":
value = thisDate.toTimeString();
break;
// locale
case "locale":
value = thisDate.toLocaleString();
break;
// localeDate
case "localeDate":
value = thisDate.toLocaleDateString();
break;
// localeTime
case "localeTime":
value = thisDate.toLocaleTimeString();
break;
// Default case
default:
value = "";
break;
}
formattedValueCache[type] = value;
return value;
};
const formattedDate = format.replace(
/\b(h|hh|H|HH|m|mm|s|ss|S|SS|SSS|EEE|EEEE|d|dd|M|MM|MMM|MMMM|yy|yyyy|aa|full|UTC|ISO|dateString|timeString|locale|localeDate|localeTime)\b/g,
(match) => getFormattedValue(match)
);
return formattedDate;
};
// src/constants/time.constants.ts
var TIME_CONSTANTS = {
YEAR_TO_MILLISECONDS: 31536e6,
MONTH_TO_MILLISECONDS: 2592e6,
DAY_TO_MILLISECONDS: 864e5,
HOUR_TO_MILLISECONDS: 36e5,
MINUTE_TO_MILLISECONDS: 6e4,
SECOND_TO_MILLISECONDS: 1e3
};
// src/date-time-difference/date-time-difference.ts
function dateTimeDifference(props = {}) {
const { timeFrom, timeTo, format = "full" } = props;
const calculateTimeFrom = !("timeFrom" in props) ? (/* @__PURE__ */ new Date()).getTime() : new Date(timeFrom).getTime();
const calculateTimeTo = !("timeTo" in props) ? (/* @__PURE__ */ new Date()).getTime() : new Date(timeTo).getTime();
if (isNaN(calculateTimeFrom) || isNaN(calculateTimeTo)) {
const invalidTimeFrom = isNaN(calculateTimeFrom) ? `Invalid From Date` : "";
const separator = isNaN(calculateTimeFrom) && isNaN(calculateTimeTo) ? ` & ` : "";
const invalidTimeTo = isNaN(calculateTimeTo) ? `Invalid To Date` : "";
return `${invalidTimeFrom}${separator}${invalidTimeTo}`;
}
const totalMillisecond = Math.abs(calculateTimeTo - calculateTimeFrom);
const multiplyValue = calculateTimeTo < calculateTimeFrom ? -1 : 1;
const totalDiffCache = {};
const getTotalDiff = (type) => {
if (totalDiffCache[type] !== void 0) return totalDiffCache[type];
let value = 0;
switch (type) {
// Millisecond
case "millisecond":
value = totalMillisecond * multiplyValue;
break;
// Second
case "second":
value = totalMillisecond / 1e3 * multiplyValue;
break;
// Minute
case "minute":
value = totalMillisecond / (1e3 * 60) * multiplyValue;
break;
// Hour
case "hour":
value = totalMillisecond / (1e3 * 60 * 60) * multiplyValue;
break;
// Day
case "day":
value = totalMillisecond / (1e3 * 60 * 60 * 24) * multiplyValue;
break;
// Month
case "month":
value = totalMillisecond / (1e3 * 60 * 60 * 24 * 30) * multiplyValue;
break;
// Year
case "year":
value = totalMillisecond / TIME_CONSTANTS.YEAR_TO_MILLISECONDS * multiplyValue;
break;
// Default case
default:
value = 0;
break;
}
totalDiffCache[type] = value;
return value;
};
const getNetDiff = () => {
let millisecond = totalMillisecond % TIME_CONSTANTS.YEAR_TO_MILLISECONDS;
let second = Math.floor(millisecond / 1e3);
let minute = Math.floor(second / 60);
let hour = Math.floor(minute / 60);
let day = Math.floor(hour / 24);
let month = Math.floor(day / 30);
const year = Math.floor(totalMillisecond / TIME_CONSTANTS.YEAR_TO_MILLISECONDS);
millisecond = millisecond % 1e3;
second = second % 60;
minute = minute % 60;
hour = hour % 24;
day = day % 30;
month = month % 12;
return {
millisecond,
second,
minute,
hour,
day,
month,
year
};
};
if (format === "full") {
const diff = getNetDiff();
const { millisecond, second, minute, hour, day, month, year } = diff;
if (year <= 0 && month <= 0 && day <= 0 && hour <= 0 && minute <= 0 && second <= 0 && millisecond <= 0) {
return "Same Time";
}
const yearValue = year > 0 ? `${year * multiplyValue}year ` : "";
const monthValue = month > 0 ? `${month * multiplyValue}month ` : "";
const dayValue = day > 0 ? `${day * multiplyValue}day ` : "";
const hourValue = hour > 0 ? `${hour * multiplyValue}hour ` : "";
const minuteValue = minute > 0 ? `${minute * multiplyValue}minute ` : "";
const secondValue = second > 0 ? `${second * multiplyValue}second ` : "";
const millisecondValue = millisecond > 0 ? `${millisecond * multiplyValue}millisecond` : "";
const result = `${yearValue}${monthValue}${dayValue}${hourValue}${minuteValue}${secondValue}${millisecondValue}`.trim();
return result;
}
if (format === "full-short-unit") {
const diff = getNetDiff();
const { year, month, day, hour, minute, second, millisecond } = diff;
if (year === 0 && month === 0 && day === 0 && hour === 0 && minute === 0 && second === 0 && millisecond === 0) {
return "Same Time";
}
const yearValue = year > 0 ? `${year * multiplyValue}yr ` : "";
const monthValue = month > 0 ? `${month * multiplyValue}mo ` : "";
const dayValue = day > 0 ? `${day * multiplyValue}day ` : "";
const hourValue = hour > 0 ? `${hour * multiplyValue}hr ` : "";
const minuteValue = minute > 0 ? `${minute * multiplyValue}min ` : "";
const secondValue = second > 0 ? `${second * multiplyValue}sec ` : "";
const millisecondValue = millisecond > 0 ? `${millisecond * multiplyValue}msec` : "";
const result = `${yearValue}${monthValue}${dayValue}${hourValue}${minuteValue}${secondValue}${millisecondValue}`.trim();
return result;
}
if (format === "object") {
const diff = getNetDiff();
const { year, month, day, hour, minute, second, millisecond } = diff;
return {
millisecond: millisecond * multiplyValue,
second: second * multiplyValue,
minute: minute * multiplyValue,
hour: hour * multiplyValue,
day: day * multiplyValue,
month: month * multiplyValue,
year: year * multiplyValue
};
}
if (format === "object-total") {
return {
millisecond: totalMillisecond * multiplyValue,
second: totalMillisecond / 1e3 * multiplyValue,
minute: totalMillisecond / (1e3 * 60) * multiplyValue,
hour: totalMillisecond / (1e3 * 60 * 60) * multiplyValue,
day: totalMillisecond / (1e3 * 60 * 60 * 24) * multiplyValue,
month: totalMillisecond / (1e3 * 60 * 60 * 24 * 30) * multiplyValue,
year: totalMillisecond / (1e3 * 60 * 60 * 24 * 30 * 12) * multiplyValue
};
}
return getTotalDiff(format);
}
// src/index-to-name/index-to-name.ts
var indexToDay = (index, format = "long") => {
if (index < 0 || index > 6) return "Invalid Index";
return format === "short" ? daysShort[index] : daysFull[index];
};
var indexToMonth = (index, format = "long") => {
if (index < 0 || index > 11) return "Invalid Index";
return format === "short" ? monthsShort[index] : monthsFull[index];
};
// src/add-subtract-time/add-subtract-time.ts
var addSubtractTime = (props) => {
const { date, value, type, format = "full", useUTC } = props;
const thisDate = !("date" in props) ? /* @__PURE__ */ new Date() : date instanceof Date ? date : new Date(date);
if (isNaN(thisDate.getTime())) return "Invalid Date";
const valueToMultiply = {
year: TIME_CONSTANTS.YEAR_TO_MILLISECONDS,
month: TIME_CONSTANTS.MONTH_TO_MILLISECONDS,
day: TIME_CONSTANTS.DAY_TO_MILLISECONDS,
hour: TIME_CONSTANTS.HOUR_TO_MILLISECONDS,
min: TIME_CONSTANTS.MINUTE_TO_MILLISECONDS,
sec: TIME_CONSTANTS.SECOND_TO_MILLISECONDS,
msec: 1
};
const givenTimeInMilliseconds = thisDate.getTime();
const newTimeInMilliseconds = givenTimeInMilliseconds + value * valueToMultiply[type];
const outputFormat = formatDateTime({ date: newTimeInMilliseconds, format, useUTC });
return outputFormat;
};
// src/is-leap-year/is-leap-year.ts
var isLeapYear = (year) => {
const value = Number(typeof year === "undefined" ? (/* @__PURE__ */ new Date()).getFullYear() : year);
if (isNaN(value) || value < 0) return false;
return value % 4 === 0 && value % 100 !== 0 || value % 400 === 0;
};
// src/is-valid-date/is-valid-date.ts
var checkIfAllSeparatorsAreValid = (date, format) => {
const dateSeparators = date.match(/[^a-zA-Z0-9]+/g) || [];
const formatSeparators = format.match(/[^a-zA-Z0-9]+/g) || [];
if (formatSeparators.length !== dateSeparators.length) return false;
for (const [index, separator] of formatSeparators.entries()) {
if (separator !== dateSeparators[index]) return false;
}
return true;
};
var checkIfAllTokensAreValid = (tokens, tokenValues) => {
const allowedCharacters = ["EEE", "EEEE", "day", "dd", "MM", "MMM", "MMMM", "month", "yy", "yyyy", "year"];
if (tokens.length !== tokenValues.length) return false;
for (const token of tokens) {
if (!allowedCharacters.includes(token)) return false;
}
return true;
};
var getDaysOfMonth = (date, year) => {
const weekdays = [];
Array.from({ length: 12 }, (_, month) => {
const shortDay = new Date(year, month, date).toLocaleDateString("en-US", { weekday: "short" });
const fullDay = new Date(year, month, date).toLocaleDateString("en-US", { weekday: "long" });
if (!weekdays.includes(shortDay)) weekdays.push(shortDay);
if (!weekdays.includes(fullDay)) weekdays.push(fullDay);
});
return weekdays;
};
var isValidDate = (date, format) => {
let isValid = false;
try {
const newDate = new Date(date);
if (newDate instanceof Date && !isNaN(newDate.getTime())) isValid = true;
} catch (error) {
console.error(error);
}
if (isValid || !format || typeof date !== "string") return isValid;
if (!checkIfAllSeparatorsAreValid(date, format)) return false;
const tokens = format.match(/[a-zA-Z0-9]+/g) || [];
const tokenValues = date.match(/[a-zA-Z0-9]+/g) || [];
if (!checkIfAllTokensAreValid(tokens, tokenValues)) return false;
const monthsWith31Days = ["00", "02", "04", "06", "07", "09", "11"];
let yearValue = void 0;
let monthValue = void 0;
let dateValue = void 0;
let dayValue = void 0;
for (const [index, token] of tokens.entries()) {
const value = tokenValues[index];
if (!value) return false;
if (token === "yy" || token === "yyyy" || token === "year") {
if (token === "yy" && value.length !== 2) return false;
if (token === "yyyy" && value.length !== 4) return false;
if (token === "year" && value.length !== 2 && value.length !== 4) return false;
const yearInNumber = parseInt(value);
if (isNaN(yearInNumber) || yearInNumber < 0 || yearInNumber > 9999) return false;
const yearValuePadded = padNumber(yearInNumber, 4);
if (yearValue === void 0) yearValue = yearValuePadded;
else if (yearValue.slice(-2) !== yearValuePadded.slice(-2)) return false;
}
if (token === "MM" || token === "MMM" || token === "MMMM" || token === "month") {
let monthIndex = -1;
const evaluateMonthInDigits = () => {
const monthInNumber = parseInt(value);
if (isNaN(monthInNumber) || monthInNumber < 1 || monthInNumber > 12) return false;
monthIndex = monthInNumber - 1;
};
if (token === "MM") evaluateMonthInDigits();
if (token === "MMM") monthIndex = monthsShort.indexOf(value);
if (token === "MMMM") monthIndex = monthsFull.indexOf(value);
if (token === "month") {
if (!isNaN(parseInt(value))) evaluateMonthInDigits();
if (value.length === 3) {
const valueFromShort = monthsShort.indexOf(value);
if (valueFromShort !== -1) monthIndex = valueFromShort;
} else {
const valueFromFull = monthsFull.indexOf(value);
if (valueFromFull !== -1) monthIndex = valueFromFull;
}
}
if (monthIndex === -1) return false;
if (monthValue === void 0) monthValue = monthIndex;
else if (monthValue !== monthIndex) return false;
}
if (token === "dd") {
const dateInNumber = parseInt(value);
if (isNaN(dateInNumber) || dateInNumber < 1 || dateInNumber > 31) return false;
if (dateValue === void 0) dateValue = dateInNumber;
else if (dateValue !== dateInNumber) return false;
}
if (token === "EEE" || token === "EEEE" || token === "day") {
let dayIndex = -1;
if (token === "EEE") dayIndex = daysShort.indexOf(value);
if (token === "EEEE") dayIndex = daysFull.indexOf(value);
if (token === "day") {
if (value.length === 3) {
const valueFromShort = daysShort.indexOf(value);
if (valueFromShort !== -1) dayIndex = valueFromShort;
} else {
const valueFromFull = daysFull.indexOf(value);
if (valueFromFull !== -1) dayIndex = valueFromFull;
}
}
if (dayIndex === -1) return false;
if (dayValue === void 0) dayValue = dayIndex;
else if (dayValue !== dayIndex) return false;
}
}
if (dateValue && monthValue) {
if (dateValue > 29 && monthValue === 1) return false;
if (dateValue === 29 && monthValue === 1 && yearValue && !isLeapYear(yearValue)) return false;
if (dateValue === 31 && !monthsWith31Days.includes(padNumber(monthValue))) return false;
}
if (dayValue && dateValue && yearValue) {
if (monthValue) {
const dayShort = new Date(parseInt(yearValue), monthValue, dateValue).toLocaleDateString("en-US", {
weekday: "short"
});
const dayLong = new Date(parseInt(yearValue), monthValue, dateValue).toLocaleDateString("en-US", {
weekday: "long"
});
if (dayShort !== daysShort[dayValue] && dayLong !== daysFull[dayValue]) return false;
} else {
const possibleDaysWithThisDate = getDaysOfMonth(dateValue, parseInt(yearValue));
if (!possibleDaysWithThisDate.includes(daysShort[dayValue]) && !possibleDaysWithThisDate.includes(daysFull[dayValue])) {
return false;
}
}
}
return true;
};
// src/get-next-occurrence/get-next-occurrence.ts
var getNextOccurrence = (day, startDate = /* @__PURE__ */ new Date()) => {
const date = new Date(startDate);
if (!(date instanceof Date) || isNaN(date.getTime())) return "Invalid date";
const requiredDayIndex = daysFull.indexOf(day);
const currentDayIndex = date.getUTCDay();
const daysToAdd = requiredDayIndex - currentDayIndex + (requiredDayIndex < currentDayIndex ? 7 : 0);
date.setUTCDate(date.getUTCDate() + daysToAdd);
return date.toUTCString();
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
addSubtractTime,
dateTimeDifference,
formatDateTime,
getNextOccurrence,
indexToDay,
indexToMonth,
isLeapYear,
isValidDate
});