Skip to content

bug(DateAdapter): Date comparison is only checking partial info #28613

@ThomasPrioul

Description

@ThomasPrioul

Is this a regression?

  • Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

I'm developing an app with Material DatePicker and Luxon Date Adapter.
I gave my users the possibility to input seconds, milliseconds or full ISO date strings into my app's date inputs.
This works well except when pasting certain dates without deleting the input's value first (replacing value with CTRL+V).

I found out why, I was pasting dates which were on the same day (but different time values) as the previous date.

Video of the problem:
datepicker-bug

https://github.com/angular/components/assets/15314924/f19fc5e0-f019-474c-b854-85a177b86703

Checking the source code reveals that in the date-adapter.ts file, dates are only compared using year/month/day instead of relying on the native's type when applicable.

compareDate(first: D, second: D): number {
return (
this.getYear(first) - this.getYear(second) ||
this.getMonth(first) - this.getMonth(second) ||
this.getDate(first) - this.getDate(second)
);
}

And the method sameDate() is called by MatDatePickerInputBase, and its result is based on the previous method's result:

sameDate(first: D | null, second: D | null): boolean {
if (first && second) {
let firstValid = this.isValid(first);
let secondValid = this.isValid(second);
if (firstValid && secondValid) {
return !this.compareDate(first, second);
}
return firstValid == secondValid;
}
return first == second;
}

Neither method is overriden in luxon-date-adapter to use something more robust.
Using my own date adapter worked as expected with this snippet:

@Injectable()
export class DemoDateAdapter extends LuxonDateAdapter {
  public override compareDate(first: DateTime<boolean>, second: DateTime<boolean>): number {
    return +first - +second;
  }
}

This fixed the problem for Luxon but for any other adapter not overloading this method (including native dates) the problem arises.

The DateAdapter interface and class does not account for milliseconds (there is no dateAdapter.getMillis), perhaps it should ?

Reproduction

I have a demo app of a lib I'm managing having the problem :
https://thomasprioul.github.io/mdl-angular-libs/#/home/forms
Steps to reproduce:

  1. Use a material app with datepicker inputs and Luxon Date Adapter
  2. Use the following provider (in app or component) to support long date formats
export const DEFAULT_DATEFORMAT_PROVIDER: Provider = {
  provide: MAT_DATE_FORMATS,
  useValue: <MatDateFormats>{
    ...MAT_LUXON_DATE_FORMATS,
    display: {
      ...MAT_LUXON_DATE_FORMATS.display,
      monthLabel: 'LLL yyyy',
      dateInput: ['D', 'D T', 'D TT', 'D TT.SSS', 'D TT.SSSZ'],
    },
    parse: {
      ...MAT_LUXON_DATE_FORMATS.parse,
      dateInput: ['D TT.SSSZ', 'D TT.SSS', 'D TT', 'D T', 'D'],
    },
  },
};
  1. Input a date with a timestamp
  2. CTRL+V another date with same day but different timestamp
  3. Form value does not change and date is reset to previous value when losing focus on the input

Expected Behavior

Correct detection of "different date" on CTRL+V

Actual Behavior

New input is considered as "equal date" when it is not

Environment

  • Angular: 17.1.1
  • CDK/Material: 17.1.1
  • Browser(s): any
  • Operating System (e.g. Windows, macOS, Ubuntu): any

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs triageThis issue needs to be triaged by the team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions