UNPKG

@sgx4u/date-time-utils

Version:

A date-time utility library

557 lines (544 loc) 20.5 kB
"use strict"; 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 });