UNPKG

@akala/core

Version:
173 lines 7.22 kB
// import { Parser, ParsedString } from '../parser/parser.js'; // import { Formatter, FormatterFactory } from './common.js'; // import { module } from '../helpers.js'; import ErrorWithStatus, { HttpStatusCode } from "../errorWithStatus.js"; import { lazy } from "../helpers.js"; import { StringCursor } from "../parser/parser.js"; const formats = { h: Date.prototype.getUTCHours, m: Date.prototype.getUTCMinutes, y: Date.prototype.getUTCFullYear, M: function () { return this.getUTCMonth() + 1; }, d: Date.prototype.getDate, s: Date.prototype.getUTCSeconds, sss: Date.prototype.getUTCMilliseconds, }; const formatsFormatter = (locale) => ({ h: function () { return formats.h.call(this).toString(); }, m: function () { return formats.m.call(this).toString(); }, M: function () { return formats.M.call(this).toString(); }, d: function () { return formats.d.call(this).toString(); }, s: function () { return formats.s.call(this).toString(); }, sss: function () { return formats.sss.call(this).toString(); }, y: function () { const y = formats.y.call(this); if (y >= 2000) return (y - 2000).toString(); return (y - 1900).toString(); }, hh: function () { return formats.h.call(this).toString().padStart(2, '0'); }, mm: function () { return formats.m.call(this).toString().padStart(2, '0'); }, MM: function () { return formats.M.call(this).toString().padStart(2, '0'); }, dd: function () { return formats.d.call(this).toString().padStart(2, '0'); }, ss: function () { return formats.s.call(this).toString().padStart(2, '0'); }, yy: function () { return formats.y.call(this).toString().substring(2); }, MMM: function () { return new Intl.DateTimeFormat(locale, { month: 'narrow' }).formatToParts(this).find(x => x.type == "month").value; }, MMMM: function () { return new Intl.DateTimeFormat(locale, { month: 'long' }).formatToParts(this).find(x => x.type == "month").value; }, ddd: function () { return new Intl.DateTimeFormat(locale, { weekday: 'narrow' }).formatToParts(this).find(x => x.type == "weekday").value; }, dddd: function () { return new Intl.DateTimeFormat(locale, { weekday: 'long' }).formatToParts(this).find(x => x.type == "weekday").value; }, yyy: function () { return formats.y.call(this).toString(); }, yyyy: function () { return formats.y.call(this).toString(); }, char: function (s) { return function () { return s; }; } }); function readUpToNDigits(s, n) { let value = s.char; for (; n >= 0; n--) { s.offset++; if (!isNaN(Number(s.char))) value += s.char; else break; } const result = Number(value); if (isNaN(result)) throw new ErrorWithStatus(HttpStatusCode.BadRequest, 'The provided string does not match the expected format'); return result; } const formatsParser = { h: function (s, date) { date.setUTCHours(readUpToNDigits(s, 2)); }, m: function (s, date) { date.setUTCMinutes(readUpToNDigits(s, 2)); }, M: function (s, date) { date.setUTCMonth(readUpToNDigits(s, 2) - 1); }, d: function (s, date) { date.setUTCDate(readUpToNDigits(s, 2)); }, s: function (s, date) { date.setUTCSeconds(readUpToNDigits(s, 2)); }, sss: function (s, date) { date.setUTCMilliseconds(readUpToNDigits(s, 8)); }, y: function (s, date) { const n = readUpToNDigits(s, 2); n >= 50 ? date.setUTCFullYear(n + 1900) : date.setUTCFullYear(n + 2000); }, hh: function (s, date) { date.setUTCHours(readUpToNDigits(s, 2)); }, mm: function (s, date) { date.setUTCMinutes(readUpToNDigits(s, 2)); }, MM: function (s, date) { date.setUTCMonth(readUpToNDigits(s, 2) - 1); }, dd: function (s, date) { date.setUTCDate(readUpToNDigits(s, 2)); }, ss: function (s, date) { date.setUTCSeconds(readUpToNDigits(s, 2)); }, yy: function (s, date) { const n = readUpToNDigits(s, 2); n >= 50 ? date.setUTCFullYear(n + 1900) : date.setUTCFullYear(n + 2000); }, yyy: function (s, date) { date.setUTCFullYear(readUpToNDigits(s, 4)); }, yyyy: function (s, date) { date.setUTCFullYear(readUpToNDigits(s, 4)); }, skip: function (s, date) { s.offset++; } }; /** * Parses and formats dates according to the specified format string. * * @param format - The date format string (e.g., 'yyyy-MM-dd'). * @returns An object with format and parse functions for date conversion. */ export function formatParser(format, locale) { if (!format) format = 'yyyy-MM-dd'; const init = lazy(() => { const formatters = []; const parsers = []; let offset = 0; const localeFormatters = formatsFormatter(locale); for (let i = offset; i < format.length; i++) { if (i > 0 && format[i - 1] != format[i] || i == format.length - 1) { const f = format.substring(offset, i); formatters.push(localeFormatters[f] ?? localeFormatters.char(f)); parsers.push(formatsParser[f] ?? formatsParser.skip); offset = i; } } return { formatters, parsers }; }); return { /** * Formats a Date object into a string using the configured format. * * @param value - The Date to format. * @returns Formatted date string. */ format(value) { return init().formatters.reduce((previous, current) => previous + current.call(value), ''); }, /** * Parses a date string into a Date object using the configured format. * * @param value - The date string to parse. * @returns Parsed Date object. * @throws {Error} If the input doesn't match the format. */ parse(value) { const result = new Date(Date.UTC(0, 0, 0, 0, 0, 0, 0)); if (typeof value == 'string' && value) { const s = new StringCursor(value); init().parsers.forEach(current => current(s, result)); } return result; } }; } /** * Formatter for converting dates to strings and vice versa. */ export default class DateFormatter { dateFormat; /** * Creates a date formatter with the specified format. * * @param dateFormat - The format string (e.g., 'yyyy-MM-dd'). */ constructor(dateFormat) { if (typeof dateFormat == 'string') this.dateFormat = formatParser(dateFormat, undefined); else this.dateFormat = formatParser(dateFormat?.format, dateFormat?.locale); } /** * Parses a formatted date string back into a Date object. * * @param {string} value - The date string to parse. * @returns {Date} The parsed date. */ unformat(value) { return this.dateFormat.parse(value); } /** * Converts a Date object to a formatted string. * * @param {Date} value - The Date to format. * @returns {string} Formatted date string. */ format(value) { return this.dateFormat.format(value); } } //# sourceMappingURL=date.js.map