day incorrect in angular material datepicker

佐手、 提交于 2019-12-02 20:47:07

Two days ago, at https://github.com/angular/material2/issues/7167, Silthus posted his workaround that overrides the MomentJsDataAdapter. I tried it and it worked as a charm from anywhere in the globe.

First he added a MomentUtcDateAdapter that extends MomentDateAdapter

import { Inject, Injectable, Optional } from '@angular/core';
import { MAT_DATE_LOCALE } from '@angular/material';   
import { MomentDateAdapter } from '@angular/material-moment-adapter';
import { Moment } from 'moment';
import * as moment from 'moment';

@Injectable()
export class MomentUtcDateAdapter extends MomentDateAdapter {

  constructor(@Optional() @Inject(MAT_DATE_LOCALE) dateLocale: string) {
    super(dateLocale);
  }

  createDate(year: number, month: number, date: number): Moment {
    // Moment.js will create an invalid date if any of the components are out of bounds, but we
    // explicitly check each case so we can throw more descriptive errors.
    if (month < 0 || month > 11) {
      throw Error(`Invalid month index "${month}". Month index has to be between 0 and 11.`);
    }

    if (date < 1) {
      throw Error(`Invalid date "${date}". Date has to be greater than 0.`);
    }

    let result = moment.utc({ year, month, date }).locale(this.locale);

    // If the result isn't valid, the date must have been out of bounds for this month.
    if (!result.isValid()) {
      throw Error(`Invalid date "${date}" for month with index "${month}".`);
    }

    return result;
  }
}

And then in the AppModule component, you have to do this:

providers: [
    ...
    { provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
    { provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS },
    { provide: DateAdapter, useClass: MomentUtcDateAdapter },
    ...
],

OPTION 1: Had same issue and solved it in backed (Java) Can you solve this in your backend code.
Presenting java code in case if anyone needs the same help. concept should be similar for other server side technologies too.

Simulated the same bug and following are the analysis.

PRINT Via JSON | "startdate": "2018-02-08T18:30:00.000Z" .

PRINT BEFORE SUBMIT >>Fri Feb 09 2018 00:00:00 GMT+0530 (IST)

public static String dateConversion(String dt) {

        Instant timestamp = Instant.parse(dt);
        ZonedDateTime isttime = timestamp.atZone(ZoneId.of("Asia/Kolkata"));
        System.out.println(isttime);

        System.out.println(DateTimeFormatter.ofPattern("dd-MM-yyyy").format(isttime));
        return DateTimeFormatter.ofPattern("dd-MM-yyyy").format(isttime);
    }

OPTION 2: (solution in frontend) I have not tried this option but the documentation seems very clear.
https://maggiepint.com/2016/05/14/moment-js-shows-the-wrong-date/ Check this out.

Angular material date picker does not support different time zones at the moment and it gives you an UTC time offset. But to me it is not a problem as i save the output string to my database and when i return it back to user the browser shows the correct date time object. Try this in your console(im in +01 zone) and you will see the selected date:

new Date('2018-02-08T23:00:00.000Z')
Fri Feb 09 2018 00:00:00 GMT+0100 (CET)

Another solution is to modify your date object before saving to database which is not the best practice.

Lastly, If you are using Moment.js in your app you could give the MomentDateAdapter a try and see if it helps you. Just add the MatMomentDateModule to your application as described here.

https://github.com/angular/material2/issues/7167#issuecomment-402061126

You can change the default behaviour to parse dates as UTC by providing the MAT_MOMENT_DATA_ADAPTER_OPTIONS and setting it to useUtc: true.

@NgModule({ 
    imports: [MatDatepickerModule, MatMomentDateModule], 
    providers: [ 
        { provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } } 
    ] 
})

Maybe it will be helpful for someone. It is my example method in which i erase TimeZone OffSet from component date

  addPriceListPeriod(priceListId: number, periodDateFrom: Date) {

    let UTCDate = Date.UTC(periodDateFrom.getFullYear(), periodDateFrom.getMonth(), periodDateFrom.getDate()) - periodDateFrom.getTimezoneOffset();

    periodDateFrom = new Date(UTCDate);

    const tempObject = {
      priceListId,
      fromDate: periodDateFrom
    }
    return this.httpClient.post('PriceLists/addPriceListPeriod', tempObject);
  }

thanks to @ankit-raonka answer here : https://stackoverflow.com/a/48761312/6423656

using ControlValueAccessor solved my issue and here is a working example : https://stackblitz.com/edit/angular-dlxnmx?file=app%2Fcva-date.component.ts

Thanks for every one for answers , i think this issue could also resolved using parse method of moment date adapter but i like the ControlValueAccessor try as i control all the input aspects + reduce the code written when i want to use it in my html .

Just use option useUtc: true for MatMomentDateAdapter:

import { MatMomentDateModule, MAT_MOMENT_DATE_ADAPTER_OPTIONS } from '@angular/material-moment-adapter';

@NgModule({
  exports: [
    MatMomentDateModule,
    // ...
  ],
  providers: [
    { provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }
  ],
})
export class MaterialModule { }

If You using Reactive Forms and do this.form.get("dateField").value you must cast it as a Date before submit.

It'll be something like:

save() {
  let obj = new MyObj();
  obj.myDate = new Date(this.form.get("mydateField").value);
  this.service.save(obj);
}

The solution stackblitz works great, but if you are not storing the timestamp in Database, then you need to convert back the date to UTC format while retrieving it from database before assigning to the datepicker.

const dbDate = getDbDate(); // '2018-02-09T00:00:00.000Z'

const updateDate = new Date(
      Date.UTC(dbDate.getFullYear(), dbDate.getMonth(), dbDate.getDate())
    ).toISOString();

now assign the updatedDate to the datepicker, hope this helps.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!