day incorrect in angular material datepicker
Solution 1
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 },
...
],
Solution 2
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 CustomModule { }
Solution 3
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);
}
Solution 4
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 } }
]
})
Solution 5
@Bruno_Cerecetto's code works fine but there is small issue. When a user type date in text box instead of choosing date with datepicker then his code does't work it reduce one day again. To work properly with the above code you need to override parse method also. Parse method called every time when a user type in the text box. Here is the code that works for me. I think it may help someone.
parse(value: any, parseFormat: string | string[]): Moment | null {
console.log(value)
if (value && typeof value === 'string') {
return moment.utc(value, parseFormat, this.locale, true);
}
return value ? moment.utc(value).locale(this.locale) : null;
}
Related videos on Youtube
Comments
-
Motaz Homsi almost 2 years
When I select a date I see the correct date in the field but, when I save, the datepicker send the day before the date I have selected ( 3 hours offset ) i am using angular reactive form and MatMomentDateModule for date picker .
the problem is related to timezones but i just want to save the same date that the user enter to database .
Code repreduced here : https://stackblitz.com/edit/angular-material-moment-adapter-example-kdk9nk?file=app%2Fapp.module.ts
issue related to this on githup :
https://github.com/angular/material2/issues/7167
Any help is appreciated , and i think a lot of developers need a solution for this .
-
Noé KlK about 5 yearsi answered it here : stackoverflow.com/questions/37495089/… (works but its raw)
-
Noé KlK about 5 yearsi answered it here its simple and quick : stackoverflow.com/questions/37495089/…
-
-
Motaz Homsi over 6 yearsi am using PHP and i think its right to convert timezoned date to timestamp and then convert it again to any other required format but i am searching for a solution for all app without convert date inputs before i add it to mysql because i have a lot of views with date inputs , i think i will go with this if i did not found a global solution for mt2 datepicker to handle this . and thanks for your answer :-)
-
Motaz Homsi over 6 yearsGreat , i was saving the record as datetime in mysql , so when ever i update the date i get the previous day , now saving the record as string solve my problem , thanks a lot
-
Motaz Homsi over 6 yearsactually i tried to use MatMomentDateModule to solve this but i can't get it to work as i want , if you see the code that i repreduced in the main question you will find it and you can edit it to try it , i think that would be the real solution if you can give an example because a lot of developers need to save the date as "datetime" for DB quering purposes .
-
pouyada over 6 yearsIm not sure that it works. I didn't try as normally we don't need Moment in an angular app. Anyway i think we can save the produced date also as a datetime in DB. I will try it Monday and let you know.
-
Motaz Homsi over 6 yearsThanks a lot @pouyada , i am appreciate your help , i will wait for your test :-)
-
pouyada over 6 yearsI tried to insert this date format to mysql but it does not accept it as a dateTime, so you need to convert it which is not recommended. Regarding to
MomentDateAdapter
, it is not suppoeted in older versions of angular material. you should use newer version ( recommended ) or install it from HERE -
Motaz Homsi over 6 yearsi am using angular material 5.0.3 in my real app , i am including MatMomentDateModule for MomentDateAdapter to be included as the docs explain here . i think i have to use parse method of this adapter to change it using moment js to be in UTC or any other format the mysql accept it as datetime without changing it in backend , but i tried a lot without any success , now i am trying using ControlValueAccessor to change output value of datepicker .
-
Motaz Homsi about 6 yearshere is a stackblitz for solution stackblitz.com/edit/…
-
D33 about 6 yearsIt worked for us but we had to override also these three methods: today, parse and deserialize.
-
Achyuth Kodali almost 5 yearsSilthus's adapter works like a charm, but I have a requirement to set the format for the date. How can I achieve that alongside timezone adapter? my date format: "DD MMM YYYY" // 15 jul 2019
-
Md. Sabbir Ahamed over 4 yearsThanks a lot, it's remove my pain, working as expected
-
jenson-button-event over 4 yearsthis still takes an hour off when using e.g.
{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' }
-
Johnathan Li about 4 yearsThis method is not working when user mannually type the date inside the text box. it didn't trigger the function.
-
Luis Ruiz Figueroa almost 4 yearsIt works when you select the date, but if the date already comes from the provider, it delays one day
-
Deitsch almost 3 yearsNice one, should be higher up!
-
Deitsch almost 3 yearsFor the issue raised by @JohnathanLi look at the answer of Pias Uddin Jibon
-
Senthilkumar Ramasamy almost 3 yearsNice. It worked. But the MatMoment Data Module has to be installed separately as this is not a part of material module. The below should help. npm install @angular/material-moment-adapter reference: material.angular.io/components/datepicker/overview
-
Serkan Sipahi over 2 yearsThank you, that was the missing (to provide it also in deps) part for me.
-
PrazSam over 2 yearsThis is the correct and simple answer. It works. But It's much appreciated if someone can explain why this happens and what happens behind the scene if we add MatMomentDateAdapter?
-
Tomek about 2 yearsIf you're also providing
MomentDateAdapter
asDateAdapter
then you need to inject that options object there too:{ provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS] }
-
Hello about 2 yearsThis one is the only correct solution for me. All thew others are not working even using moment and MAT_MOMENT_DATE_ADAPTER_OPTIONS.
-
toxaq about 2 yearsMoment is no longer in active development. Not the ideal ongoing solution.