@akala/core
Version:
173 lines • 7.22 kB
JavaScript
// 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