parsing a short year format with date-fns?

96 Views Asked by At

How can I use the Date-Fns Adapter for Angular Material to parse short date formats without an explicit separator? For example, 010123 => 01.01.2023. With the whole year it works as expected: 01012023 => 01.01.2023

My actual thought process would be ddMMyy but according to the Unicode Documentation:

However, "yy" requests just the two low-order digits of the year, zero-padded as necessary.

So the Unicode tokens would reference the year 0023 instead of 2023.

My question is how can I adjust this context to get this desired behavior?

Here is my CUSTOM_FORMAT:

export const CUSTOM_FORMAT: MatDateFormats = {
  parse: {
    dateInput: ["dd.MM.yyyy", "dd/MM/yyyy", "dd,MM,yyyy", "ddMMyyyy", "ddMMyy"],
  },
  display: {
    dateInput: "dd.MM.yyyy",
    monthYearLabel: "MMM yyyy",
    dateA11yLabel: "MMMM d, y",
    monthYearA11yLabel: "MMM yyyy"
  },
};
1

There are 1 best solutions below

0
stax On BEST ANSWER

I fixed my problem by writing a CustomDateAdapter that overrides the default parse function of the DateFnsAdapter.

In my CustomDateAdapter:

override parse(value: any, parseFormat: string | string[]): Date | null {
        if (typeof value === 'string' && value.length > 0) {
            if (!parseFormat.length) {
                throw Error('Formats array must not be empty.');
            }

            // Check if the input value is in the format "ddMMyy" or "d.M.yy" or "dd.MM.yy"
            const matchWithSeparator: RegExpMatchArray = value.match(/^(\d{1,2})[.\-/](\d{1,2})[.\-/](\d{2})$/);
            const matchWithoutSeparator: RegExpMatchArray = value.match(/^(\d{2})(\d{2})(\d{2})$/);

            // Gets first two digits of current year 
            const firstTwoDigitsOfCurrentYear: string = new Date().getFullYear().toString().slice(0,2);

            // Convert the matched parts to a valid date string "DD.MM.YYYY"
            if (matchWithSeparator) {
                value = `${matchWithSeparator[1]}.${matchWithSeparator[2]}.${firstTwoDigitsOfCurrentYear}${matchWithSeparator[3]}`;
            } else if (matchWithoutSeparator) {
                value = `${matchWithoutSeparator[1]}.${matchWithoutSeparator[2]}.${firstTwoDigitsOfCurrentYear}${matchWithoutSeparator[3]}`;
            }

            // General parsing logic for multiple formats declared in shared.module
            for (const currentFormat of parseFormat) {
                const fromFormat: Date = parse(value, currentFormat, new Date(), { locale: this.locale });

                if (this.isValid(fromFormat)) {
                    return fromFormat;
                }
            }

            return this.invalid();
        } else if (typeof value === 'number') {
            return new Date(value);
        } else if (value instanceof Date) {
            return this.clone(value);
        }

        return null;
    }