112 lines
4.0 KiB
JavaScript
112 lines
4.0 KiB
JavaScript
// Composables
|
|
import { useDate } from "./date/date.js"; // Utilities
|
|
import { toRef } from 'vue';
|
|
import { consoleWarn, propsFactory } from "../util/index.js"; // Types
|
|
// Types
|
|
class DateFormatSpec {
|
|
constructor(order,
|
|
// mdy | dmy | ymd
|
|
separator // / | - | .
|
|
) {
|
|
this.order = order;
|
|
this.separator = separator;
|
|
}
|
|
get format() {
|
|
return this.order.split('').map(sign => `${sign}${sign}`).join(this.separator).replace('yy', 'yyyy');
|
|
}
|
|
static canBeParsed(v) {
|
|
if (typeof v !== 'string') return false;
|
|
const lowercase = v.toLowerCase();
|
|
return ['y', 'm', 'd'].every(sign => lowercase.includes(sign)) && ['/', '-', '.'].some(sign => v.includes(sign));
|
|
}
|
|
static parse(v) {
|
|
if (!DateFormatSpec.canBeParsed(v)) {
|
|
throw new Error(`[${v}] cannot be parsed into date format specification`);
|
|
}
|
|
const order = v.toLowerCase().split('').filter((c, i, all) => 'dmy'.includes(c) && all.indexOf(c) === i).join('');
|
|
const separator = ['/', '-', '.'].find(sign => v.includes(sign));
|
|
return new DateFormatSpec(order, separator);
|
|
}
|
|
}
|
|
export const makeDateFormatProps = propsFactory({
|
|
inputFormat: {
|
|
type: String,
|
|
validator: v => !v || DateFormatSpec.canBeParsed(v)
|
|
}
|
|
}, 'date-format');
|
|
export function useDateFormat(props, locale) {
|
|
const adapter = useDate();
|
|
function inferFromLocale() {
|
|
const localeForDateFormat = locale.value ?? 'en-US';
|
|
const formatFromLocale = Intl.DateTimeFormat(localeForDateFormat, {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit'
|
|
}).format(adapter.toJsDate(adapter.parseISO('1999-12-07'))).replace(/(07)|(٠٧)|(٢٩)|(۱۶)|(০৭)/, 'dd').replace(/(12)|(١٢)|(٠٨)|(۰۹)|(১২)/, 'mm').replace(/(1999)|(2542)|(١٩٩٩)|(١٤٢٠)|(۱۳۷۸)|(১৯৯৯)/, 'yyyy').replace(/[^ymd\-/.]/g, '').replace(/\.$/, '');
|
|
if (!DateFormatSpec.canBeParsed(formatFromLocale)) {
|
|
consoleWarn(`Date format inferred from locale [${localeForDateFormat}] is invalid: [${formatFromLocale}]`);
|
|
return 'mm/dd/yyyy';
|
|
}
|
|
return formatFromLocale;
|
|
}
|
|
const currentFormat = toRef(() => {
|
|
return DateFormatSpec.canBeParsed(props.inputFormat) ? DateFormatSpec.parse(props.inputFormat) : DateFormatSpec.parse(inferFromLocale());
|
|
});
|
|
function parseDate(dateString) {
|
|
function parseDateParts(text) {
|
|
const parts = text.trim().split(currentFormat.value.separator);
|
|
return {
|
|
y: Number(parts[currentFormat.value.order.indexOf('y')]),
|
|
m: Number(parts[currentFormat.value.order.indexOf('m')]),
|
|
d: Number(parts[currentFormat.value.order.indexOf('d')])
|
|
};
|
|
}
|
|
function validateDateParts(dateParts) {
|
|
const {
|
|
y: year,
|
|
m: month,
|
|
d: day
|
|
} = dateParts;
|
|
if (!year || !month || !day) return null;
|
|
if (month < 1 || month > 12) return null;
|
|
if (day < 1 || day > 31) return null;
|
|
return {
|
|
year: autoFixYear(year),
|
|
month,
|
|
day
|
|
};
|
|
}
|
|
function autoFixYear(year) {
|
|
const currentYear = adapter.getYear(adapter.date());
|
|
if (year > 100 || currentYear % 100 >= 50) {
|
|
return year;
|
|
}
|
|
const currentCentury = ~~(currentYear / 100) * 100;
|
|
return year < 50 ? currentCentury + year : currentCentury - 100 + year;
|
|
}
|
|
const dateParts = parseDateParts(dateString);
|
|
const validatedParts = validateDateParts(dateParts);
|
|
if (!validatedParts) return null;
|
|
const {
|
|
year,
|
|
month,
|
|
day
|
|
} = validatedParts;
|
|
const pad = v => String(v).padStart(2, '0');
|
|
return adapter.parseISO(`${year}-${pad(month)}-${pad(day)}`);
|
|
}
|
|
function isValid(text) {
|
|
return !!parseDate(text);
|
|
}
|
|
function formatDate(value) {
|
|
const parts = adapter.toISO(value).split('T')[0].split('-');
|
|
return currentFormat.value.order.split('').map(sign => parts['ymd'.indexOf(sign)]).join(currentFormat.value.separator);
|
|
}
|
|
return {
|
|
isValid,
|
|
parseDate,
|
|
formatDate,
|
|
parserFormat: toRef(() => currentFormat.value.format)
|
|
};
|
|
}
|
|
//# sourceMappingURL=dateFormat.js.map
|