Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DatePicker with MAT_DATE_LOCALE = en-GB parses incorrectly if the day is changed? #7823

Closed
zijianhuang opened this issue Oct 16, 2017 · 16 comments
Assignees

Comments

@zijianhuang
Copy link

Bug:

With DatePicker, in the NgModule, I have the following settings:

  providers: [{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' },         
  { provide: LOCALE_ID, useValue: "en-GB" },

If I input a string like "10/12/2017", the picker will has 12 Oct 2017 selected, instead of 10 Dec 2017 since en-GB should use DD/MM/YYYY.

Others features of the DatePicker are working fine.

What are the steps to reproduce?

In the plnkr example provided at https://material.angular.io/components/datepicker/overview, in main.ts, just add settings to NgModule:

  providers: [{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' },         
  { provide: LOCALE_ID, useValue: "en-GB" },

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular 4.4.4, Material: Beta 12.

@luqeckr
Copy link

luqeckr commented Oct 20, 2017

you don't have to include both MAT_DATE_LOCALE and LOCALE_ID

i also use dd/mm/yyyy format (id-ID locale) and has the same problem
but the date picker toggle give me DD/MM/YYYY and it's valid

when i try to type manually in the input element
the format in input element still use MM/DD/YYYY

so 24/7/2017 give me invalid status, when typing manually
but valid status when picking from the picker button.

@aljabali
Copy link

+1 as Iuqeckr

@nikhildev
Copy link

I have the same issue as well. I wrote a custom adapter for it as well. When picking from the calendar, the date is valid, but entering the date manually makes it invalid

@NaifousBS
Copy link

+1 same problem

@oleksandr-tkach
Copy link

yeah. same issue

@NaifousBS
Copy link

NaifousBS commented Oct 31, 2017

I think it's the same issue as here : #7143

@mmalerba
Copy link
Contributor

The NativeDateAdapter doesn't support DD/MM/YYYY, I recommend using the MomentDateAdapter or extending the NativeDateAdapter and overriding the parse method

@oleksandr-tkach
Copy link

I found solution here:
#675 (comment)
Take a look at response from @arlowhite

@oleksandr-tkach
Copy link

oleksandr-tkach commented Oct 31, 2017

I changed this moment date adapter a bit. This works for me:

import { DateAdapter, MatDateFormats } from '@angular/material';
import { isMoment, Moment } from 'moment';
import * as moment from 'moment';

export const MOMENT_DATE_FORMATS: MatDateFormats = {
  parse: {
    dateInput: 'D/MM/YYYY'
  },
  display: {
    dateInput: 'DD/MM/YYYY',
    monthYearLabel: 'MMMM Y',
    dateA11yLabel: 'LL',
    monthYearA11yLabel: 'MMMM Y'
  }
};

const dateNames: string[] = [];
for (let date = 1; date <= 31; date++) {
  dateNames.push(String(date));
}

export class MomentDateAdapter extends DateAdapter<Moment> {

  private localeData = moment.localeData();

  getYear(date: Moment): number {
    return date.year();
  }

  getMonth(date: Moment): number {
    return date.month();
  }

  getDate(date: Moment): number {
    return date.date();
  }

  getDayOfWeek(date: Moment): number {
    return date.day();
  }

  getMonthNames(style: 'long' | 'short' | 'narrow'): string[] {
    switch (style) {
      case 'long':
        return this.localeData.months();
      case 'short':
        return this.localeData.monthsShort();
      case 'narrow':
        return this.localeData.monthsShort().map(month => month[0]);
    }
  }

  getDateNames(): string[] {
    return dateNames;
  }

  getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[] {
    switch (style) {
      case 'long':
        return this.localeData.weekdays();
      case 'short':
        return this.localeData.weekdaysShort();
      case 'narrow':
        return this.localeData.weekdaysShort();
    }
  }

  getYearName(date: Moment): string {
    return String(date.year());
  }

  getFirstDayOfWeek(): number {
    return this.localeData.firstDayOfWeek();
  }

  getNumDaysInMonth(date: Moment): number {
    return date.daysInMonth();
  }

  clone(date: Moment): Moment {
    return date.clone();
  }

  createDate(year: number, month: number, date: number): Moment {
    return moment([year, month, date]);
  }

  today(): Moment {
    return moment();
  }

  parse(value: any, parseFormat: any): Moment {
    let m = moment(value, parseFormat, true);
    if (!m.isValid()) {
      m = moment(value);
    }
    if (m.isValid()) {
      return m;
    }
    return null;
  }

  format(date: Moment, displayFormat: any): string {
    if (date) {
      return date.format(displayFormat);
    }
    return '';
  }

  addCalendarYears(date: Moment, years: number): Moment {
    return date.clone().add(years, 'y');
  }

  addCalendarMonths(date: Moment, months: number): Moment {
    return date.clone().add(months, 'M');
  }

  addCalendarDays(date: Moment, days: number): Moment {
    return date.clone().add(days, 'd');
  }

  setLocale(locale: any): void {
    this.localeData = moment.localeData(locale);
  }

  compareDate(first: Moment, second: Moment): number {
    return first.diff(second, 'seconds', true);
  }

  sameDate(first: any | Moment, second: any | Moment): boolean {
    if (first == null) {
      return second == null;
    } else if (isMoment(first)) {
      return first.isSame(second);
    }
    return super.sameDate(first, second);
  }

  clampDate(date: Moment, min?: any | Moment, max?: any | Moment): Moment {
    if (min && date.isBefore(min)) {
      return min;
    } else if (max && date.isAfter(max)) {
      return max;
    }
    return date;
  }

  isValid(date: Moment): boolean {
    return date.isValid();
  };

  isDateInstance(obj: Object): boolean {
    return moment.isMoment(obj);
  };

  toIso8601(date: Moment): string {
    return date.format();
  };

  fromIso8601(iso8601String: string): Moment {
    return moment(iso8601String);
  };

}

And don't forget to update main application module with providers:

{provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS},
{provide: DateAdapter, useClass: MomentDateAdapter}

@NaifousBS
Copy link

Can you provide a plunker with this example please ?

@oleksandr-tkach
Copy link

@NaifousBS sorry, I have no time right now, but I'll try to do that ASAP.

@NaifousBS
Copy link

NaifousBS commented Nov 8, 2017

I made some changes and it works for me now :) :

  • Add the Moment Date Adapter in your project called 'moment-date-adapter.ts' from https://github.com/angular/material2/blob/master/src/material-moment-adapter/adapter/moment-date-adapter.ts
  • In this adapter add a line in the "imports zone" for the locale :
    import 'moment/locale/fr';
  • Don't forget to add this in your module :
    { provide: MAT_DATE_LOCALE, useValue: 'fr-FR' }, { provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS }, { provide: DateAdapter, useClass: MomentDateAdapter },
    and of course import those variables with
    import { MomentDateAdapter, MOMENT_DATE_FORMATS } from './moment-date-adapter';

Stackblitz example : https://stackblitz.com/edit/angular-date-picker-sample-fr

@mmalerba
Copy link
Contributor

mmalerba commented Nov 8, 2017

The official material one is also published to npm now: https://www.npmjs.com/package/@angular/material-moment-adapter. Second to last example on the datepicker examples page shows it in action: https://material.angular.io/components/datepicker/examples

@timbophillips
Copy link

@angular angular deleted a comment from torabian Dec 1, 2018
@bresleveloper
Copy link

you don't have to include both MAT_DATE_LOCALE and LOCALE_ID

i also use dd/mm/yyyy format (id-ID locale) and has the same problem
but the date picker toggle give me DD/MM/YYYY and it's valid

when i try to type manually in the input element
the format in input element still use MM/DD/YYYY

so 24/7/2017 give me invalid status, when typing manually
but valid status when picking from the picker button.

i would like to see a fix to that please

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants