when pasting date time, if multiple formats match and one matches the current display order, use that format for parsing
This commit is contained in:
@@ -89,6 +89,7 @@ import { ThemeType } from '@/core/theme.ts';
|
||||
import { NumeralSystem } from '@/core/numeral.ts';
|
||||
import {
|
||||
type DateTime,
|
||||
type DateFormatOrder,
|
||||
MeridiemIndicator,
|
||||
KnownDateTimeFormat
|
||||
} from '@/core/datetime.ts';
|
||||
@@ -120,6 +121,8 @@ const theme = useTheme();
|
||||
const {
|
||||
tt,
|
||||
getCurrentNumeralSystemType,
|
||||
getLongDateFormatOrder,
|
||||
getShortDateFormatOrder,
|
||||
parseDateTimeFromLongDateTime,
|
||||
parseDateTimeFromShortDateTime,
|
||||
formatDateTimeToLongDateTime
|
||||
@@ -144,6 +147,8 @@ const secondInput = useTemplateRef<VAutocomplete>('secondInput');
|
||||
|
||||
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
|
||||
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
||||
const longDateFormatOrder = computed<DateFormatOrder>(() => getLongDateFormatOrder());
|
||||
const shortDateFormatOrder = computed<DateFormatOrder>(() => getShortDateFormatOrder());
|
||||
|
||||
const dateTime = computed<Date>({
|
||||
get: () => {
|
||||
@@ -245,10 +250,10 @@ function onPaste(event: ClipboardEvent): void {
|
||||
|
||||
text = text.trim();
|
||||
|
||||
const formats = KnownDateTimeFormat.detect(text);
|
||||
const formats = KnownDateTimeFormat.detect(text, longDateFormatOrder.value, shortDateFormatOrder.value);
|
||||
let dt: DateTime | undefined = undefined;
|
||||
|
||||
if (formats && formats.length === 1) {
|
||||
if (formats && (formats.length === 1 || (formats.length > 1 && formats[0]!.type === longDateFormatOrder.value && formats[0]!.type === shortDateFormatOrder.value))) {
|
||||
dt = parseDateTimeFromKnownDateTimeFormat(text, formats[0] as KnownDateTimeFormat);
|
||||
|
||||
if (dt) {
|
||||
|
||||
+176
-109
@@ -345,108 +345,18 @@ export class MeridiemIndicator {
|
||||
}
|
||||
}
|
||||
|
||||
export class KnownDateTimeFormat {
|
||||
private static readonly allInstances: KnownDateTimeFormat[] = [];
|
||||
|
||||
public static readonly DefaultDateTime = new KnownDateTimeFormat('YYYY-MM-DD HH:mm:ss', /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
public static readonly DefaultDateTimeWithTimezone = new KnownDateTimeFormat('YYYY-MM-DD HH:mm:ssZ', /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](Z|[+-](0[0-9]|1[0-4]):[0-5][0-9])$/);
|
||||
public static readonly DefaultDateTimeWithoutSecond = new KnownDateTimeFormat('YYYY-MM-DD HH:mm', /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]$/);
|
||||
public static readonly DefaultDate = new KnownDateTimeFormat('YYYY-MM-DD', /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
|
||||
public static readonly RFC3339 = new KnownDateTimeFormat('YYYY-MM-DDTHH:mm:ssZ', /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](Z|[+-](0[0-9]|1[0-4]):[0-5][0-9])$/);
|
||||
|
||||
public static readonly YYYYMMDDSlashWithTime = new KnownDateTimeFormat('YYYY/MM/DD HH:mm:ss', /^\d{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
public static readonly MMDDYYYYSlashWithTime = new KnownDateTimeFormat('MM/DD/YYYY HH:mm:ss', /^(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])\/\d{4} ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
public static readonly DDMMYYYYSlashWithTime = new KnownDateTimeFormat('DD/MM/YYYY HH:mm:ss', /^(0[1-9]|[1-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/\d{4} ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
|
||||
public static readonly YYYYMMDDDotWithTime = new KnownDateTimeFormat('YYYY.MM.DD HH:mm:ss', /^\d{4}\.(0[1-9]|1[0-2])\.(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
public static readonly MMDDYYYYDotWithTime = new KnownDateTimeFormat('MM.DD.YYYY HH:mm:ss', /^(0[1-9]|1[0-2])\.(0[1-9]|[1-2][0-9]|3[0-1])\.\d{4} ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
public static readonly DDMMYYYYDotWithTime = new KnownDateTimeFormat('DD.MM.YYYY HH:mm:ss', /^(0[1-9]|[1-2][0-9]|3[0-1])\.(0[1-9]|1[0-2])\.\d{4} ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
|
||||
public static readonly MMDDYYYYDash = new KnownDateTimeFormat('MM-DD-YYYY', /^(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])-\d{4}$/);
|
||||
public static readonly DDMMYYYYDash = new KnownDateTimeFormat('DD-MM-YYYY', /^(0[1-9]|[1-2][0-9]|3[0-1])-(0[1-9]|1[0-2])-\d{4}$/);
|
||||
|
||||
public static readonly YYYYMMDDSlash = new KnownDateTimeFormat('YYYY/MM/DD', /^\d{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
public static readonly MMDDYYYYSlash = new KnownDateTimeFormat('MM/DD/YYYY', /^(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])\/\d{4}$/);
|
||||
public static readonly DDMMYYYYSlash = new KnownDateTimeFormat('DD/MM/YYYY', /^(0[1-9]|[1-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/\d{4}$/);
|
||||
|
||||
public static readonly YYYYMDSlash = new KnownDateTimeFormat('YYYY/M/D', /^\d{4}\/([1-9]|1[0-2])\/([1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
public static readonly MDYYYYSlash = new KnownDateTimeFormat('M/D/YYYY', /^([1-9]|1[0-2])\/([1-9]|[1-2][0-9]|3[0-1])\/\d{4}$/);
|
||||
public static readonly DMYYYYSlash = new KnownDateTimeFormat('D/M/YYYY', /^([1-9]|[1-2][0-9]|3[0-1])\/([1-9]|1[0-2])\/\d{4}$/);
|
||||
|
||||
public static readonly YYYYMMDDDot = new KnownDateTimeFormat('YYYY.MM.DD', /^\d{4}\.(0[1-9]|1[0-2])\.(0[1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
public static readonly MMDDYYYYDot = new KnownDateTimeFormat('MM.DD.YYYY', /^(0[1-9]|1[0-2])\.(0[1-9]|[1-2][0-9]|3[0-1])\.\d{4}$/);
|
||||
public static readonly DDMMYYYYDot = new KnownDateTimeFormat('DD.MM.YYYY', /^(0[1-9]|[1-2][0-9]|3[0-1])\.(0[1-9]|1[0-2])\.\d{4}$/);
|
||||
|
||||
public static readonly YYYYMDDot = new KnownDateTimeFormat('YYYY.M.D', /^\d{4}\.([1-9]|1[0-2])\.([1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
public static readonly MDYYYYDot = new KnownDateTimeFormat('M.D.YYYY', /^([1-9]|1[0-2])\.([1-9]|[1-2][0-9]|3[0-1])\.\d{4}$/);
|
||||
public static readonly DMYYYYDot = new KnownDateTimeFormat('D.M.YYYY', /^([1-9]|[1-2][0-9]|3[0-1])\.([1-9]|1[0-2])\.\d{4}$/);
|
||||
|
||||
public static readonly YYYYMMDD = new KnownDateTimeFormat('YYYYMMDD', /^\d{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
|
||||
public readonly format: string;
|
||||
private readonly regex: RegExp;
|
||||
|
||||
private constructor(format: string, regex: RegExp) {
|
||||
this.format = format;
|
||||
this.regex = regex;
|
||||
|
||||
KnownDateTimeFormat.allInstances.push(this);
|
||||
}
|
||||
|
||||
public isValid(dateTime: string): boolean {
|
||||
return this.regex.test(dateTime);
|
||||
}
|
||||
|
||||
public static values(): KnownDateTimeFormat[] {
|
||||
return KnownDateTimeFormat.allInstances;
|
||||
}
|
||||
|
||||
public static detect(dateTime: string): KnownDateTimeFormat[] | undefined {
|
||||
const result: KnownDateTimeFormat[] = [];
|
||||
|
||||
for (const format of KnownDateTimeFormat.allInstances) {
|
||||
if (format.isValid(dateTime)) {
|
||||
result.push(format);
|
||||
}
|
||||
}
|
||||
|
||||
return result.length > 0 ? result : undefined;
|
||||
}
|
||||
|
||||
public static detectMulti(dateTimes: string[]): KnownDateTimeFormat[] | undefined {
|
||||
const detectedCounts: Record<string, number> = {};
|
||||
|
||||
for (const dateTime of dateTimes) {
|
||||
const detectedFormats = KnownDateTimeFormat.detect(dateTime);
|
||||
|
||||
if (detectedFormats) {
|
||||
for (const format of detectedFormats) {
|
||||
detectedCounts[format.format] = (detectedCounts[format.format] || 0) + 1;
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const result: KnownDateTimeFormat[] = [];
|
||||
|
||||
for (const format of KnownDateTimeFormat.allInstances) {
|
||||
if (detectedCounts[format.format] === dateTimes.length) {
|
||||
result.push(format);
|
||||
}
|
||||
}
|
||||
|
||||
return result.length > 0 ? result : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export const LANGUAGE_DEFAULT_DATE_TIME_FORMAT_VALUE: number = 0;
|
||||
|
||||
export enum DateFormatOrder {
|
||||
YMD = 1,
|
||||
MDY = 2,
|
||||
DMY = 3
|
||||
}
|
||||
|
||||
export interface DateFormat {
|
||||
readonly type: number;
|
||||
readonly key: string;
|
||||
readonly isMonthAfterYear: boolean;
|
||||
readonly order: DateFormatOrder;
|
||||
}
|
||||
|
||||
type DateFormatTypeName = 'YYYYMMDD' | 'MMDDYYYY' | 'DDMMYYYY';
|
||||
@@ -456,22 +366,22 @@ export class LongDateFormat implements DateFormat {
|
||||
private static readonly allInstancesByType: Record<number, LongDateFormat> = {};
|
||||
private static readonly allInstancesByTypeName: Record<string, LongDateFormat> = {};
|
||||
|
||||
public static readonly YYYYMMDD = new LongDateFormat(1, 'YYYYMMDD', 'yyyy_mm_dd', true);
|
||||
public static readonly MMDDYYYY = new LongDateFormat(2, 'MMDDYYYY', 'mm_dd_yyyy', false);
|
||||
public static readonly DDMMYYYY = new LongDateFormat(3, 'DDMMYYYY', 'dd_mm_yyyy', false);
|
||||
public static readonly YYYYMMDD = new LongDateFormat(1, 'YYYYMMDD', 'yyyy_mm_dd', DateFormatOrder.YMD);
|
||||
public static readonly MMDDYYYY = new LongDateFormat(2, 'MMDDYYYY', 'mm_dd_yyyy', DateFormatOrder.MDY);
|
||||
public static readonly DDMMYYYY = new LongDateFormat(3, 'DDMMYYYY', 'dd_mm_yyyy', DateFormatOrder.DMY);
|
||||
|
||||
public static readonly Default = LongDateFormat.YYYYMMDD;
|
||||
|
||||
public readonly type: number;
|
||||
public readonly typeName: string;
|
||||
public readonly key: string;
|
||||
public readonly isMonthAfterYear: boolean;
|
||||
public readonly order: DateFormatOrder;
|
||||
|
||||
private constructor(type: number, typeName: DateFormatTypeName, key: string, isMonthAfterYear: boolean) {
|
||||
private constructor(type: number, typeName: DateFormatTypeName, key: string, order: DateFormatOrder) {
|
||||
this.type = type;
|
||||
this.typeName = typeName;
|
||||
this.key = key;
|
||||
this.isMonthAfterYear = isMonthAfterYear;
|
||||
this.order = order;
|
||||
|
||||
LongDateFormat.allInstances.push(this);
|
||||
LongDateFormat.allInstancesByType[type] = this;
|
||||
@@ -496,22 +406,22 @@ export class ShortDateFormat implements DateFormat {
|
||||
private static readonly allInstancesByType: Record<number, ShortDateFormat> = {};
|
||||
private static readonly allInstancesByTypeName: Record<string, ShortDateFormat> = {};
|
||||
|
||||
public static readonly YYYYMMDD = new ShortDateFormat(1, 'YYYYMMDD', 'yyyy_mm_dd', true);
|
||||
public static readonly MMDDYYYY = new ShortDateFormat(2, 'MMDDYYYY', 'mm_dd_yyyy', false);
|
||||
public static readonly DDMMYYYY = new ShortDateFormat(3, 'DDMMYYYY', 'dd_mm_yyyy', false);
|
||||
public static readonly YYYYMMDD = new ShortDateFormat(1, 'YYYYMMDD', 'yyyy_mm_dd', DateFormatOrder.YMD);
|
||||
public static readonly MMDDYYYY = new ShortDateFormat(2, 'MMDDYYYY', 'mm_dd_yyyy', DateFormatOrder.MDY);
|
||||
public static readonly DDMMYYYY = new ShortDateFormat(3, 'DDMMYYYY', 'dd_mm_yyyy', DateFormatOrder.DMY);
|
||||
|
||||
public static readonly Default = ShortDateFormat.YYYYMMDD;
|
||||
|
||||
public readonly type: number;
|
||||
public readonly typeName: string;
|
||||
public readonly key: string;
|
||||
public readonly isMonthAfterYear: boolean;
|
||||
public readonly order: DateFormatOrder;
|
||||
|
||||
private constructor(type: number, typeName: DateFormatTypeName, key: string, isMonthAfterYear: boolean) {
|
||||
private constructor(type: number, typeName: DateFormatTypeName, key: string, order: DateFormatOrder) {
|
||||
this.type = type;
|
||||
this.typeName = typeName;
|
||||
this.key = key;
|
||||
this.isMonthAfterYear = isMonthAfterYear;
|
||||
this.order = order;
|
||||
|
||||
ShortDateFormat.allInstances.push(this);
|
||||
ShortDateFormat.allInstancesByType[type] = this;
|
||||
@@ -626,6 +536,163 @@ export class ShortTimeFormat implements TimeFormat {
|
||||
}
|
||||
}
|
||||
|
||||
export class KnownDateTimeFormat {
|
||||
private static readonly allInstances: KnownDateTimeFormat[] = [];
|
||||
private static readonly allYMDInstances: KnownDateTimeFormat[] = [];
|
||||
private static readonly allMDYInstances: KnownDateTimeFormat[] = [];
|
||||
private static readonly allDMYInstances: KnownDateTimeFormat[] = [];
|
||||
|
||||
public static readonly DefaultDateTime = new KnownDateTimeFormat('YYYY-MM-DD HH:mm:ss', DateFormatOrder.YMD, /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
public static readonly DefaultDateTimeWithTimezone = new KnownDateTimeFormat('YYYY-MM-DD HH:mm:ssZ', DateFormatOrder.YMD, /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](Z|[+-](0[0-9]|1[0-4]):[0-5][0-9])$/);
|
||||
public static readonly DefaultDateTimeWithoutSecond = new KnownDateTimeFormat('YYYY-MM-DD HH:mm', DateFormatOrder.YMD, /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]$/);
|
||||
public static readonly DefaultDate = new KnownDateTimeFormat('YYYY-MM-DD', DateFormatOrder.YMD, /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
|
||||
public static readonly RFC3339 = new KnownDateTimeFormat('YYYY-MM-DDTHH:mm:ssZ', DateFormatOrder.YMD, /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](Z|[+-](0[0-9]|1[0-4]):[0-5][0-9])$/);
|
||||
|
||||
public static readonly YYYYMMDDSlashWithTime = new KnownDateTimeFormat('YYYY/MM/DD HH:mm:ss', DateFormatOrder.YMD, /^\d{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
public static readonly MMDDYYYYSlashWithTime = new KnownDateTimeFormat('MM/DD/YYYY HH:mm:ss', DateFormatOrder.MDY, /^(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])\/\d{4} ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
public static readonly DDMMYYYYSlashWithTime = new KnownDateTimeFormat('DD/MM/YYYY HH:mm:ss', DateFormatOrder.DMY, /^(0[1-9]|[1-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/\d{4} ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
|
||||
public static readonly YYYYMMDDDotWithTime = new KnownDateTimeFormat('YYYY.MM.DD HH:mm:ss', DateFormatOrder.YMD, /^\d{4}\.(0[1-9]|1[0-2])\.(0[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
public static readonly MMDDYYYYDotWithTime = new KnownDateTimeFormat('MM.DD.YYYY HH:mm:ss', DateFormatOrder.MDY, /^(0[1-9]|1[0-2])\.(0[1-9]|[1-2][0-9]|3[0-1])\.\d{4} ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
public static readonly DDMMYYYYDotWithTime = new KnownDateTimeFormat('DD.MM.YYYY HH:mm:ss', DateFormatOrder.DMY, /^(0[1-9]|[1-2][0-9]|3[0-1])\.(0[1-9]|1[0-2])\.\d{4} ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/);
|
||||
|
||||
public static readonly MMDDYYYYDash = new KnownDateTimeFormat('MM-DD-YYYY', DateFormatOrder.MDY, /^(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])-\d{4}$/);
|
||||
public static readonly DDMMYYYYDash = new KnownDateTimeFormat('DD-MM-YYYY', DateFormatOrder.DMY, /^(0[1-9]|[1-2][0-9]|3[0-1])-(0[1-9]|1[0-2])-\d{4}$/);
|
||||
|
||||
public static readonly YYYYMMDDSlash = new KnownDateTimeFormat('YYYY/MM/DD', DateFormatOrder.YMD, /^\d{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
public static readonly MMDDYYYYSlash = new KnownDateTimeFormat('MM/DD/YYYY', DateFormatOrder.MDY, /^(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])\/\d{4}$/);
|
||||
public static readonly DDMMYYYYSlash = new KnownDateTimeFormat('DD/MM/YYYY', DateFormatOrder.DMY, /^(0[1-9]|[1-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/\d{4}$/);
|
||||
|
||||
public static readonly YYYYMDSlash = new KnownDateTimeFormat('YYYY/M/D', DateFormatOrder.YMD, /^\d{4}\/([1-9]|1[0-2])\/([1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
public static readonly MDYYYYSlash = new KnownDateTimeFormat('M/D/YYYY', DateFormatOrder.MDY, /^([1-9]|1[0-2])\/([1-9]|[1-2][0-9]|3[0-1])\/\d{4}$/);
|
||||
public static readonly DMYYYYSlash = new KnownDateTimeFormat('D/M/YYYY', DateFormatOrder.DMY, /^([1-9]|[1-2][0-9]|3[0-1])\/([1-9]|1[0-2])\/\d{4}$/);
|
||||
|
||||
public static readonly YYYYMMDDDot = new KnownDateTimeFormat('YYYY.MM.DD', DateFormatOrder.YMD, /^\d{4}\.(0[1-9]|1[0-2])\.(0[1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
public static readonly MMDDYYYYDot = new KnownDateTimeFormat('MM.DD.YYYY', DateFormatOrder.MDY, /^(0[1-9]|1[0-2])\.(0[1-9]|[1-2][0-9]|3[0-1])\.\d{4}$/);
|
||||
public static readonly DDMMYYYYDot = new KnownDateTimeFormat('DD.MM.YYYY', DateFormatOrder.DMY, /^(0[1-9]|[1-2][0-9]|3[0-1])\.(0[1-9]|1[0-2])\.\d{4}$/);
|
||||
|
||||
public static readonly YYYYMDDot = new KnownDateTimeFormat('YYYY.M.D', DateFormatOrder.YMD, /^\d{4}\.([1-9]|1[0-2])\.([1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
public static readonly MDYYYYDot = new KnownDateTimeFormat('M.D.YYYY', DateFormatOrder.MDY, /^([1-9]|1[0-2])\.([1-9]|[1-2][0-9]|3[0-1])\.\d{4}$/);
|
||||
public static readonly DMYYYYDot = new KnownDateTimeFormat('D.M.YYYY', DateFormatOrder.DMY, /^([1-9]|[1-2][0-9]|3[0-1])\.([1-9]|1[0-2])\.\d{4}$/);
|
||||
|
||||
public static readonly YYYYMMDD = new KnownDateTimeFormat('YYYYMMDD', DateFormatOrder.YMD, /^\d{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$/);
|
||||
|
||||
public readonly format: string;
|
||||
public readonly type: DateFormatOrder;
|
||||
private readonly regex: RegExp;
|
||||
|
||||
private constructor(format: string, type: DateFormatOrder, regex: RegExp) {
|
||||
this.format = format;
|
||||
this.type = type;
|
||||
this.regex = regex;
|
||||
|
||||
if (type === DateFormatOrder.YMD) {
|
||||
KnownDateTimeFormat.allYMDInstances.push(this);
|
||||
} else if (type === DateFormatOrder.MDY) {
|
||||
KnownDateTimeFormat.allMDYInstances.push(this);
|
||||
} else if (type === DateFormatOrder.DMY) {
|
||||
KnownDateTimeFormat.allDMYInstances.push(this);
|
||||
}
|
||||
|
||||
KnownDateTimeFormat.allInstances.push(this);
|
||||
}
|
||||
|
||||
public isValid(dateTime: string): boolean {
|
||||
return this.regex.test(dateTime);
|
||||
}
|
||||
|
||||
public static values(): KnownDateTimeFormat[] {
|
||||
return KnownDateTimeFormat.allInstances;
|
||||
}
|
||||
|
||||
public static detect(dateTime: string, longDateTimeFormatOrder: DateFormatOrder, shortDateTimeFormatOrder: DateFormatOrder): KnownDateTimeFormat[] | undefined {
|
||||
const allFormats: KnownDateTimeFormat[] = KnownDateTimeFormat.getAllFormatsByOrder(longDateTimeFormatOrder, shortDateTimeFormatOrder);
|
||||
return KnownDateTimeFormat.detectSingle(dateTime, allFormats);
|
||||
}
|
||||
|
||||
public static detectMulti(dateTimes: string[], longDateTimeFormatOrder: DateFormatOrder, shortDateTimeFormatOrder: DateFormatOrder): KnownDateTimeFormat[] | undefined {
|
||||
const detectedCounts: Record<string, number> = {};
|
||||
const allFormats: KnownDateTimeFormat[] = KnownDateTimeFormat.getAllFormatsByOrder(longDateTimeFormatOrder, shortDateTimeFormatOrder);
|
||||
|
||||
for (const dateTime of dateTimes) {
|
||||
const detectedFormats = KnownDateTimeFormat.detectSingle(dateTime, allFormats);
|
||||
|
||||
if (detectedFormats) {
|
||||
for (const format of detectedFormats) {
|
||||
detectedCounts[format.format] = (detectedCounts[format.format] || 0) + 1;
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const result: KnownDateTimeFormat[] = [];
|
||||
|
||||
for (const format of KnownDateTimeFormat.allInstances) {
|
||||
if (detectedCounts[format.format] === dateTimes.length) {
|
||||
result.push(format);
|
||||
}
|
||||
}
|
||||
|
||||
return result.length > 0 ? result : undefined;
|
||||
}
|
||||
|
||||
private static detectSingle(dateTime: string, allFormats: KnownDateTimeFormat[]): KnownDateTimeFormat[] | undefined {
|
||||
const result: KnownDateTimeFormat[] = [];
|
||||
|
||||
for (const format of allFormats) {
|
||||
if (format.isValid(dateTime)) {
|
||||
result.push(format);
|
||||
}
|
||||
}
|
||||
|
||||
return result.length > 0 ? result : undefined;
|
||||
}
|
||||
|
||||
private static getAllFormatsByOrder(longDateTimeFormatOrder: DateFormatOrder, shortDateTimeFormatOrder: DateFormatOrder): KnownDateTimeFormat[] {
|
||||
if (longDateTimeFormatOrder === DateFormatOrder.YMD && (shortDateTimeFormatOrder === DateFormatOrder.YMD || shortDateTimeFormatOrder === DateFormatOrder.MDY)) {
|
||||
return [
|
||||
...KnownDateTimeFormat.allYMDInstances,
|
||||
...KnownDateTimeFormat.allMDYInstances,
|
||||
...KnownDateTimeFormat.allDMYInstances
|
||||
];
|
||||
} else if (longDateTimeFormatOrder === DateFormatOrder.YMD && shortDateTimeFormatOrder === DateFormatOrder.DMY) {
|
||||
return [
|
||||
...KnownDateTimeFormat.allYMDInstances,
|
||||
...KnownDateTimeFormat.allDMYInstances,
|
||||
...KnownDateTimeFormat.allMDYInstances
|
||||
];
|
||||
} else if (longDateTimeFormatOrder === DateFormatOrder.MDY && (shortDateTimeFormatOrder === DateFormatOrder.MDY || shortDateTimeFormatOrder === DateFormatOrder.YMD)) {
|
||||
return [
|
||||
...KnownDateTimeFormat.allMDYInstances,
|
||||
...KnownDateTimeFormat.allYMDInstances,
|
||||
...KnownDateTimeFormat.allDMYInstances
|
||||
];
|
||||
} else if (longDateTimeFormatOrder === DateFormatOrder.MDY && shortDateTimeFormatOrder === DateFormatOrder.DMY) {
|
||||
return [
|
||||
...KnownDateTimeFormat.allMDYInstances,
|
||||
...KnownDateTimeFormat.allDMYInstances,
|
||||
...KnownDateTimeFormat.allYMDInstances
|
||||
];
|
||||
} else if (longDateTimeFormatOrder === DateFormatOrder.DMY && (shortDateTimeFormatOrder === DateFormatOrder.DMY || shortDateTimeFormatOrder === DateFormatOrder.YMD)) {
|
||||
return [
|
||||
...KnownDateTimeFormat.allDMYInstances,
|
||||
...KnownDateTimeFormat.allYMDInstances,
|
||||
...KnownDateTimeFormat.allMDYInstances
|
||||
];
|
||||
} else if (longDateTimeFormatOrder === DateFormatOrder.DMY && shortDateTimeFormatOrder === DateFormatOrder.MDY) {
|
||||
return [
|
||||
...KnownDateTimeFormat.allDMYInstances,
|
||||
...KnownDateTimeFormat.allMDYInstances,
|
||||
...KnownDateTimeFormat.allYMDInstances
|
||||
];
|
||||
} else {
|
||||
return KnownDateTimeFormat.allInstances;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export enum DateRangeScene {
|
||||
Normal = 0,
|
||||
TrendAnalysis = 1,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type TypeAndName, type TypeAndDisplayName, entries, keys } from './base.ts';
|
||||
import { KnownAmountFormat } from './numeral.ts';
|
||||
import { KnownDateTimeFormat } from './datetime.ts';
|
||||
import { type DateFormatOrder, KnownDateTimeFormat } from './datetime.ts';
|
||||
import { KnownDateTimezoneFormat } from './timezone.ts';
|
||||
import { TransactionType } from './transaction.ts';
|
||||
|
||||
@@ -165,7 +165,7 @@ export class ImportTransactionDataMapping {
|
||||
return result;
|
||||
}
|
||||
|
||||
public parseFileAutoDetectedTimeFormat(fileData: string[][] | undefined): string | undefined {
|
||||
public parseFileAutoDetectedTimeFormat(fileData: string[][] | undefined, longDateTimeFormatOrder: DateFormatOrder, shortDateTimeFormatOrder: DateFormatOrder): string | undefined {
|
||||
if (!fileData || !fileData.length || !this.isColumnMappingSet(ImportTransactionColumnType.TransactionTime)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -193,7 +193,7 @@ export class ImportTransactionDataMapping {
|
||||
}
|
||||
}
|
||||
|
||||
const detectedFormats = KnownDateTimeFormat.detectMulti(allDateTimes);
|
||||
const detectedFormats = KnownDateTimeFormat.detectMulti(allDateTimes, longDateTimeFormatOrder, shortDateTimeFormatOrder);
|
||||
|
||||
if (!detectedFormats || !detectedFormats.length || detectedFormats.length > 1) {
|
||||
return undefined;
|
||||
|
||||
+2
-2
@@ -654,7 +654,7 @@ export function parseDateTimeFromUnixTimeWithTimezoneOffset(unixTime: number, ut
|
||||
}
|
||||
|
||||
export function parseDateTimeFromKnownDateTimeFormat(dateTime: string, format: KnownDateTimeFormat): DateTime | undefined {
|
||||
const m = moment(dateTime, format.format);
|
||||
const m = moment(dateTime, format.format, true);
|
||||
|
||||
if (!m.isValid()) {
|
||||
return undefined;
|
||||
@@ -664,7 +664,7 @@ export function parseDateTimeFromKnownDateTimeFormat(dateTime: string, format: K
|
||||
}
|
||||
|
||||
export function parseDateTimeFromString(dateTime: string, format: string): DateTime | undefined {
|
||||
const m = moment(dateTime, format);
|
||||
const m = moment(dateTime, format, true);
|
||||
|
||||
if (!m.isValid()) {
|
||||
return undefined;
|
||||
|
||||
+15
-2
@@ -61,6 +61,7 @@ import {
|
||||
ShortDateFormat,
|
||||
LongTimeFormat,
|
||||
ShortTimeFormat,
|
||||
DateFormatOrder,
|
||||
DateRange,
|
||||
DateRangeScene,
|
||||
LANGUAGE_DEFAULT_DATE_TIME_FORMAT_VALUE
|
||||
@@ -1760,12 +1761,22 @@ export function useI18n() {
|
||||
return t(`currency.name.${currencyCode}`);
|
||||
}
|
||||
|
||||
function getLongDateFormatOrder(): DateFormatOrder {
|
||||
return getLocalizedDateTimeType(LongDateFormat.all(), LongDateFormat.values(), userStore.currentUserLongDateFormat, 'longDateFormat', LongDateFormat.Default).order;
|
||||
}
|
||||
|
||||
function getShortDateFormatOrder(): DateFormatOrder {
|
||||
return getLocalizedDateTimeType(ShortDateFormat.all(), ShortDateFormat.values(), userStore.currentUserShortDateFormat, 'shortDateFormat', ShortDateFormat.Default).order;
|
||||
}
|
||||
|
||||
function isLongDateMonthAfterYear(): boolean {
|
||||
return getLocalizedDateTimeType(LongDateFormat.all(), LongDateFormat.values(), userStore.currentUserLongDateFormat, 'longDateFormat', LongDateFormat.Default).isMonthAfterYear;
|
||||
const order: DateFormatOrder = getLongDateFormatOrder();
|
||||
return order === DateFormatOrder.YMD;
|
||||
}
|
||||
|
||||
function isShortDateMonthAfterYear(): boolean {
|
||||
return getLocalizedDateTimeType(ShortDateFormat.all(), ShortDateFormat.values(), userStore.currentUserShortDateFormat, 'shortDateFormat', ShortDateFormat.Default).isMonthAfterYear;
|
||||
const order: DateFormatOrder = getShortDateFormatOrder();
|
||||
return order === DateFormatOrder.YMD;
|
||||
}
|
||||
|
||||
function isLongTime24HourFormat(): boolean {
|
||||
@@ -2422,6 +2433,8 @@ export function useI18n() {
|
||||
getCurrentDigitGroupingType,
|
||||
getCurrentFiscalYearFormatType,
|
||||
getCurrencyName,
|
||||
getLongDateFormatOrder,
|
||||
getShortDateFormatOrder,
|
||||
isLongDateMonthAfterYear,
|
||||
isShortDateMonthAfterYear,
|
||||
isLongTime24HourFormat,
|
||||
|
||||
@@ -230,7 +230,7 @@ import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { type NameValue, type NameNumeralValue, type TypeAndDisplayName, itemAndIndex, entries } from '@/core/base.ts';
|
||||
import { type NumeralSystem, KnownAmountFormat } from '@/core/numeral.ts';
|
||||
import { KnownDateTimeFormat } from '@/core/datetime.ts';
|
||||
import { type DateFormatOrder, KnownDateTimeFormat } from '@/core/datetime.ts';
|
||||
import { KnownDateTimezoneFormat } from '@/core/timezone.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
import { ImportTransactionColumnType, ImportTransactionDataMapping } from '@/core/import_transaction.ts';
|
||||
@@ -286,6 +286,8 @@ const {
|
||||
tt,
|
||||
ti,
|
||||
getCurrentNumeralSystemType,
|
||||
getLongDateFormatOrder,
|
||||
getShortDateFormatOrder,
|
||||
getAllImportTransactionColumnTypes
|
||||
} = useI18n();
|
||||
|
||||
@@ -296,6 +298,8 @@ const countPerPage = ref<number>(10);
|
||||
const parsedFileDataColumnMapping = ref<ImportTransactionDataMapping>(ImportTransactionDataMapping.createEmpty());
|
||||
|
||||
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
||||
const longDateFormatOrder = computed<DateFormatOrder>(() => getLongDateFormatOrder());
|
||||
const shortDateFormatOrder = computed<DateFormatOrder>(() => getShortDateFormatOrder());
|
||||
const allImportTransactionColumnTypes = computed<TypeAndDisplayName[]>(() => getAllImportTransactionColumnTypes());
|
||||
|
||||
const menus = computed<ImportTransactionDefineColumnMenu[]>(() => [
|
||||
@@ -402,7 +406,7 @@ const parsedFileLinesTablePageOptions = computed<NameNumeralValue[]>(() => getTa
|
||||
|
||||
const parsedFileAllTransactionTypes = computed<string[]>(() => parsedFileDataColumnMapping.value.parseFileAllTransactionTypes(props.parsedFileData));
|
||||
const parsedFileValidMappedTransactionTypes = computed<Record<string, TransactionType>>(() => parsedFileDataColumnMapping.value.parseFileValidMappedTransactionTypes(props.parsedFileData));
|
||||
const parsedFileAutoDetectedTimeFormat = computed<string | undefined>(() => parsedFileDataColumnMapping.value.parseFileAutoDetectedTimeFormat(props.parsedFileData));
|
||||
const parsedFileAutoDetectedTimeFormat = computed<string | undefined>(() => parsedFileDataColumnMapping.value.parseFileAutoDetectedTimeFormat(props.parsedFileData, longDateFormatOrder.value, shortDateFormatOrder.value));
|
||||
const parsedFileAutoDetectedTimezoneFormat = computed<string | undefined>(() => parsedFileDataColumnMapping.value.parseFileAutoDetectedTimezoneFormat(props.parsedFileData));
|
||||
const parsedFileAutoDetectedAmountFormat = computed<string | undefined>(() => parsedFileDataColumnMapping.value.parseFileAutoDetectedAmountFormat(props.parsedFileData));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user