title: Handle separator with Material dayjs date adapter
body: <p>In my Angular application I need to swap from <a href="https://momentjs.com/" rel="nofollow noreferrer">momentjs</a> to <a href="https://day.js.org/" rel="nofollow noreferrer">dayjs</a>.
  Because I am using <a href="https://material.angular.io/" rel="nofollow noreferrer">material</a> I have to replace <code>moment-date-adapter</code> with a dayjs-date-adapter, so I write my own date adapter but I can't understand how momentjs can parse a date like <code>12122020</code> without any separator (you can see it in action <a href="https://stackblitz.com/angular/jladbrqneye?file=src%2Fapp%2Fdatepicker-moment-example.ts" rel="nofollow noreferrer">here</a>).</p>
  <p>I try to achieve it by setting this <code>MatDateFormats</code>, with an array of dateinput.
  But I don't know if it is the best solution because I don't see it in moment-date-adapter</p>
  <pre><code>MatDateFormats = {
  parse: {
      dateInput: ['D/M/YYYY', 'DMYYYY'],
  },
  display: {
      dateInput: 'DD/MM/YYYY',
      monthYearLabel: 'MMMM YYYY',
      dateA11yLabel: 'DD/MM/YYYY',
      monthYearA11yLabel: 'MMMM YYYY',
  }
  </code></pre>
  <p>}</p>
  <p>This is my <code>dayjs-date-adapter</code></p>
  <pre><code>export interface DayJsDateAdapterOptions {
  /**
   * Turns the use of utc dates on or off.
   * Changing this will change how Angular Material components like DatePicker output dates.
   * {@default false}
   */
  useUtc?: boolean;
  }
  
  /** InjectionToken for Dayjs date adapter to configure options. */
  export const MAT_DAYJS_DATE_ADAPTER_OPTIONS = new InjectionToken&lt;DayJsDateAdapterOptions&gt;(
  'MAT_DAYJS_DATE_ADAPTER_OPTIONS', {
      providedIn: 'root',
      factory: MAT_DAYJS_DATE_ADAPTER_OPTIONS_FACTORY
  });
  
  export function MAT_DAYJS_DATE_ADAPTER_OPTIONS_FACTORY(): DayJsDateAdapterOptions {
   return {
      useUtc: false
   };
  }
  
  /** Creates an array and fills it with values. */
  function range&lt;T&gt;(length: number, valueFunction: (index: number) =&gt; T): T[] {
   const valuesArray = Array(length);
   for (let i = 0; i &lt; length; i++) {
      valuesArray[i] = valueFunction(i);
   }
   return valuesArray;
  }
  
  /** Adapts Dayjs Dates for use with Angular Material. */
  export class DayjsDateAdapter extends DateAdapter&lt;Dayjs&gt; {
   private localeData: {
      firstDayOfWeek: number,
      longMonths: string[],
      shortMonths: string[],
      dates: string[],
      longDaysOfWeek: string[],
      shortDaysOfWeek: string[],
      narrowDaysOfWeek: string[]
   };
  
  constructor(@Optional() @Inject(MAT_DATE_LOCALE) public dateLocale: string,
              @Optional() @Inject(MAT_DAYJS_DATE_ADAPTER_OPTIONS) private options?: 
     DayJsDateAdapterOptions) {
      super();
  
      this.initializeParser(dateLocale);
    }
  
  private get shouldUseUtc(): boolean {
      const {useUtc}: DayJsDateAdapterOptions = this.options || {};
      return !!useUtc;
  }
  
  // TODO: Implement
  setLocale(locale: string) {
      super.setLocale(locale);
  
      const dayJsLocaleData = this.dayJs().localeData();
      this.localeData = {
          firstDayOfWeek: dayJsLocaleData.firstDayOfWeek(),
          longMonths: dayJsLocaleData.months(),
          shortMonths: dayJsLocaleData.monthsShort(),
          dates: range(31, (i) =&gt; this.createDate(2017, 0, i + 1).format('D')),
          longDaysOfWeek: range(7, (i) =&gt; this.dayJs().set('day', i).format('dddd')),
          shortDaysOfWeek: dayJsLocaleData.weekdaysShort(),
          narrowDaysOfWeek: dayJsLocaleData.weekdaysMin(),
      };
  }
  
  getYear(date: Dayjs): number {
      return this.dayJs(date).year();
  }
  
  getMonth(date: Dayjs): number {
      return this.dayJs(date).month();
  }
  
  getDate(date: Dayjs): number {
      return this.dayJs(date).date();
  }
  
  getDayOfWeek(date: Dayjs): number {
      return this.dayJs(date).day();
  }
  
  getMonthNames(style: 'long' | 'short' | 'narrow'): string[] {
      return style === 'long' ? this.localeData.longMonths : this.localeData.shortMonths;
  }
  
  getDateNames(): string[] {
      return this.localeData.dates;
  }
  
  getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[] {
      if (style === 'long') {
          return this.localeData.longDaysOfWeek;
      }
      if (style === 'short') {
          return this.localeData.shortDaysOfWeek;
      }
      return this.localeData.narrowDaysOfWeek;
  }
  
  getYearName(date: Dayjs): string {
      return this.dayJs(date).format('YYYY');
  }
  
  getFirstDayOfWeek(): number {
      return this.localeData.firstDayOfWeek;
  }
  
  getNumDaysInMonth(date: Dayjs): number {
      return this.dayJs(date).daysInMonth();
  }
  
  clone(date: Dayjs): Dayjs {
      return date.clone();
  }
  
  createDate(year: number, month: number, date: number): Dayjs {
      const returnDayjs = this.dayJs()
          .set('year', year)
          .set('month', month)
          .set('date', date);
      return returnDayjs;
  }
  
  today(): Dayjs {
      return this.dayJs();
  }
  
  parse(value: any, parseFormat: string): Dayjs | null {
      if (value &amp;&amp; typeof value === 'string') {
          return this.dayJs(value, parseFormat, this.locale);
      }
      return value ? this.dayJs(value).locale(this.locale) : null;
  }
  
  format(date: Dayjs, displayFormat: string): string {
      if (!this.isValid(date)) {
          throw Error('DayjsDateAdapter: Cannot format invalid date.');
      }
      return date.locale(this.locale).format(displayFormat);
  }
  
  addCalendarYears(date: Dayjs, years: number): Dayjs {
      return date.add(years, 'year');
  }
  
  addCalendarMonths(date: Dayjs, months: number): Dayjs {
      return date.add(months, 'month');
  }
  
  addCalendarDays(date: Dayjs, days: number): Dayjs {
      return date.add(days, 'day');
  }
  
  toIso8601(date: Dayjs): string {
      return date.toISOString();
  }
  
  
  deserialize(value: any): Dayjs | null {
      let date;
      if (value instanceof Date) {
          date = this.dayJs(value);
      } else if (this.isDateInstance(value)) {
          // NOTE: assumes that cloning also sets the correct locale.
          return this.clone(value);
      }
      if (typeof value === 'string') {
          if (!value) {
              return null;
          }
          date = this.dayJs(value).toISOString();
      }
      if (date &amp;&amp; this.isValid(date)) {
          return this.dayJs(date);
      }
      return super.deserialize(value);
  }
  
  isDateInstance(obj: any): boolean {
      return dayjs.isDayjs(obj);
  }
  
  isValid(date: Dayjs): boolean {
      return this.dayJs(date).isValid();
  }
  
  invalid(): Dayjs {
      return this.dayJs(null);
  }
  
  private dayJs(input?: any, format?: string, locale?: string): Dayjs {
      if (!this.shouldUseUtc) {
          return dayjs(input, format, locale, false);
      }
      return dayjs(input, {format, locale, utc: this.shouldUseUtc}, locale, false).utc();
  }
  
  private initializeParser(dateLocale: string) {
      if (this.shouldUseUtc) {
          dayjs.extend(utc);
      }
  
      dayjs.extend(LocalizedFormat);
      dayjs.extend(customParseFormat);
      dayjs.extend(localeData);
  
   }
  }
  </code></pre>