UNPKG

sussy-util

Version:
216 lines (215 loc) 10.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const IsSomething_1 = __importDefault(require("./IsSomething")); class DateTimeFormatter { constructor(pattern) { /** * Gets the pattern used by this formatter. * @returns {string} The pattern string. */ this.getPattern = () => this.pattern; /** * Formats the date portion (YYYY, MM, DD) of a given Date object. * @param {Date} date - The date object to format. * @returns {string} The formatted date string. * @throws {Error} Throws an error if the provided date is invalid. */ this.formatDate = (date) => { if (!IsSomething_1.default.isDate(date) || !IsSomething_1.default.isDateValid(date)) { throw new Error('Invalid date object provided.'); } let formatted = this.pattern; const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); formatted = formatted.replace(/YYYY/g, String(year)); formatted = formatted.replace(/MM/g, month); formatted = formatted.replace(/DD/g, day); return formatted; }; /** * Formats both the date and time based on the pattern. * @param {Date} date - The date object to format. * @returns {string} The formatted date-time string. * @throws {Error} Throws an error if the provided date is invalid. */ this.formatDateTime = (date) => { if (!IsSomething_1.default.isDate(date) || !IsSomething_1.default.isDateValid(date)) { throw new Error('Invalid date object provided.'); } let formatted = this.pattern; const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); formatted = formatted.replace(/YYYY/g, String(year)); formatted = formatted.replace(/MM/g, month); formatted = formatted.replace(/DD/g, day); const has12Hour = /hh/.test(this.pattern); const has24Hour = /HH/.test(this.pattern); const hours24 = date.getHours(); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); if (has12Hour) { const amPm = hours24 >= 12 ? 'PM' : 'AM'; const hours12 = hours24 % 12 || 12; const hoursStr = String(hours12).padStart(2, '0'); formatted = formatted.replace(/hh/g, hoursStr); if (/A/.test(this.pattern)) { formatted = formatted.replace(/A/g, amPm); } if (/a/.test(this.pattern)) { formatted = formatted.replace(/a/g, amPm.toLowerCase()); } } if (has24Hour) { const hoursStr = String(hours24).padStart(2, '0'); formatted = formatted.replace(/HH/g, hoursStr); } formatted = formatted.replace(/mm/g, minutes); formatted = formatted.replace(/ss/g, seconds); return formatted; }; /** * Parses a date string based on the formatter's pattern. * @param {string} dateString - The date string to parse. * @returns {Date} The parsed Date object. * @throws {Error} Throws an error if the string is invalid or the pattern is incorrect. */ this.parseDate = (dateString) => { if (typeof dateString !== 'string' || !dateString.trim()) { throw new Error('Date string must be a non-empty string.'); } const yearIndex = this.pattern.indexOf('YYYY'); const monthIndex = this.pattern.indexOf('MM'); const dayIndex = this.pattern.indexOf('DD'); if (yearIndex < 0 || monthIndex < 0 || dayIndex < 0) { throw new Error('Cannot parse date - pattern must include YYYY, MM, and DD tokens.'); } const year = parseInt(dateString.substring(yearIndex, yearIndex + 4), 10); const month = parseInt(dateString.substring(monthIndex, monthIndex + 2), 10) - 1; const day = parseInt(dateString.substring(dayIndex, dayIndex + 2), 10); if (isNaN(year) || isNaN(month) || isNaN(day)) { throw new Error('Provided date string does not match the pattern.'); } const parsedDate = new Date(year, month, day); if (parsedDate.getFullYear() !== year || parsedDate.getMonth() !== month || parsedDate.getDate() !== day) { throw new Error('Invalid date components - out of range.'); } return parsedDate; }; /** * Parses a time string based on the formatter's pattern. * @param {string} timeString - The time string to parse. * @returns {Object} An object containing hours, minutes, and seconds. * @throws {Error} Throws an error if the string is invalid or the pattern is incorrect. */ this.parseTime = (timeString) => { if (typeof timeString !== 'string' || !timeString.trim()) { throw new Error('Time string must be a non-empty string.'); } const has24Hour = /HH/.test(this.pattern); const has12Hour = /hh/.test(this.pattern); let amPmPart = ''; let baseTimeString = timeString; if ((/A/.test(this.pattern) || /a/.test(this.pattern)) && has12Hour) { const match = timeString.match(/^(.+?)(AM|PM|am|pm)$/); if (match) { baseTimeString = match[1].trim(); amPmPart = match[2].toUpperCase(); } } const parts = baseTimeString.split(':'); if (parts.length !== 3) { throw new Error('Provided time string does not match the pattern for minutes/seconds.'); } const [hoursStr, minutesStr, secondsStr] = parts; let hours = parseInt(hoursStr, 10); const minutes = parseInt(minutesStr, 10); const seconds = parseInt(secondsStr, 10); if (isNaN(hours) || isNaN(minutes) || isNaN(seconds)) { throw new Error('Provided time string does not match the pattern for minutes/seconds.'); } if (minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59) { throw new Error('Time components out of range.'); } if (has24Hour) { if (hours < 0 || hours > 23) { throw new Error('Invalid 24-hour format in time string.'); } } else if (has12Hour) { if (amPmPart === 'AM' && hours === 12) { hours = 0; } else if (amPmPart === 'PM' && hours < 12) { hours += 12; } if (hours < 0 || hours > 23) { throw new Error('Invalid 12-hour format in time string.'); } } return { hours, minutes, seconds }; }; /** * Parses a combined date-time string based on the formatter's pattern. * @param {string} dateTimeString - The date-time string to parse. * @returns {Date} The parsed Date object. * @throws {Error} Throws an error if the string is invalid or the pattern is incorrect. */ this.parseDateTime = (dateTimeString) => { if (typeof dateTimeString !== 'string' || !dateTimeString.trim()) { throw new Error('DateTime string must be a non-empty string.'); } const datePart = this.extractPart(dateTimeString, 'YYYY', 'DD'); const timePart = this.extractPart(dateTimeString, 'HH', 'ss') || this.extractPart(dateTimeString, 'hh', 'ss'); if (!datePart || !timePart) { throw new Error('Provided dateTime string does not match the pattern.'); } const tempDate = this.parseDate(datePart); const { hours, minutes, seconds } = this.parseTime(timePart); tempDate.setHours(hours, minutes, seconds, 0); return tempDate; }; /** * Extracts a substring from the given dateTime string based on tokens. * @private * @param {string} dateTimeString - The full dateTime string. * @param {'YYYY' | 'HH' | 'hh'} startToken - The starting token for extraction. * @param {'DD' | 'ss'} endToken - The ending token for extraction. * @returns {string|null} The extracted substring, or null if tokens are not found. */ this.extractPart = (dateTimeString, startToken, endToken) => { if (!this.pattern.includes(startToken) || !this.pattern.includes(endToken)) { return null; } const startIndex = this.pattern.indexOf(startToken); const endIndex = this.pattern.indexOf(endToken) + endToken.length; if (startIndex < 0 || endIndex < 0) { return null; } return dateTimeString.substring(startIndex, endIndex); }; if (typeof pattern !== 'string' || !pattern.trim()) { throw new Error('Pattern must be a non-empty string.'); } this.pattern = pattern; } } /** * Creates a new DateTimeFormatter instance with the provided pattern. * @param {string} pattern - The pattern to use for formatting and parsing dates/times. * @returns {DateTimeFormatter} A new instance of DateTimeFormatter. * @throws {Error} Throws an error if the pattern is not a non-empty string. */ DateTimeFormatter.ofPattern = (pattern) => { if (typeof pattern !== 'string' || !pattern.trim()) { throw new Error('Pattern must be a non-empty string.'); } return new DateTimeFormatter(pattern); }; exports.default = DateTimeFormatter;