день неправильный в угловом материале datepicker
Когда я выбираю дату, я вижу правильную дату в поле, но, когда я сохраняю, датапикер отправляет день до даты, которую я выбрал (смещение за 3 часа). Я использую угловую реактивную форму и MatMomentDateModule для выбора даты.
проблема связана с часовыми поясами, но я просто хочу сохранить ту же дату, которую пользователь вводит в базу данных.
Код, представленный здесь: https://stackblitz.com/edit/angular-material-moment-adapter-example-kdk9nk?file=app%2Fapp.module.ts
вопрос, связанный с этим по githup:
https://github.com/angular/material2/issues/7167
Любая помощь приветствуется, и я думаю, что многим разработчикам необходимо решение для этого.
Ответы
Ответ 1
Два дня назад, на https://github.com/angular/material2/issues/7167, Silthus опубликовал свое обходное решение, которое переопределяет MomentJsDataAdapter. Я попробовал это, и он работал как шарм из любой точки земного шара.
Сначала он добавил MomentUtcDateAdapter, который расширяет 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;
}
}
А затем в компоненте AppModule вы должны сделать это:
providers: [
...
{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
{ provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS },
{ provide: DateAdapter, useClass: MomentUtcDateAdapter },
...
],
Ответ 2
ВАРИАНТ 1: Была ли такая же проблема и решена в резервной копии (Java). Можете ли вы решить эту проблему в своем внутреннем коде.
Представление Java-кода в случае, если кому-то нужна такая же помощь. концепция должна быть аналогичной для других технологий на стороне сервера.
Имитировал ту же ошибку и следующий анализ.
PRINT через JSON | "startdate": "2018-02-08T18: 30: 00.000Z".
ПЕЧАТЬ ПЕРЕД ПРЕДСТАВЛЕНИЕМ >> Пт 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);
}
ВАРИАНТ 2: (решение во внешнем интерфейсе) Я не пробовал этот вариант, но документация кажется очень ясной.
https://maggiepint.com/2016/05/14/moment-js-shows-the-wrong-date/ Проверьте это.
Ответ 3
Уставка углового выбора даты не поддерживает различные часовые пояса на данный момент и дает вам временное смещение по UTC. Но для меня это не проблема, так как я сохраняю строку вывода в моей базе данных, и когда я возвращаю ее обратно пользователю, браузер показывает правильный объект времени. Попробуйте это в консоли (im в зоне +01), и вы увидите выбранную дату:
new Date('2018-02-08T23:00:00.000Z')
Fri Feb 09 2018 00:00:00 GMT+0100 (CET)
Другим решением является изменение объекта даты перед сохранением в базу данных, которая не является лучшей практикой.
Наконец, если вы используете Moment.js в своем приложении, вы можете попробовать MomentDateAdapter
и посмотреть, помогает ли он вам. Просто добавьте MatMomentDateModule
к вашему приложению, как описано здесь.
Ответ 4
https://github.com/angular/material2/issues/7167#issuecomment-402061126
Вы можете изменить поведение по умолчанию для синтаксического анализа дат как UTC, предоставив MAT_MOMENT_DATA_ADAPTER_OPTIONS и установив его для использованияUtc: true.
@NgModule({
imports: [MatDatepickerModule, MatMomentDateModule],
providers: [
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }
]
})
Ответ 5
Может быть, это будет кому-то полезно. Это мой пример метода, в котором я стираю TimeZone OffSet от даты компонента
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);
}
Ответ 6
спасибо @ankit-raonka ответ здесь: fooobar.com/questions/14660346/...
использование ControlValueAccessor решило мою проблему, и вот рабочий пример: https://stackblitz.com/edit/angular-dlxnmx?file=app%2Fcva-date.component.ts
Спасибо за каждый ответ, я думаю, что эта проблема также может быть решена с использованием метода синтаксиса адаптера момента date, но мне нравится ControlValueAccessor, поскольку я контролирую все аспекты ввода + уменьшаю код, написанный, когда я хочу использовать его в своем html.
Ответ 7
Вышеупомянутое решение работало очень хорошо, когда пользователь выбирает дату из средства выбора, но оно не работает, когда пользователь вводит дату в поле ввода, введите описание изображения здесь
Ответ 8
Просто используйте опцию useUtc: true
для 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 { }
Ответ 9
Решение stackblitz отлично работает, но если вы не сохраняете метку времени в базе данных, вам необходимо преобразовать дату обратно в формат UTC, извлекая ее из базы данных, прежде чем назначать ее датчику.
const dbDate = getDbDate(); // '2018-02-09T00:00:00.000Z'
const updateDate = new Date(
Date.UTC(dbDate.getFullYear(), dbDate.getMonth(), dbDate.getDate())
).toISOString();
Теперь назначьте updatedDate
для средства выбора даты, надеюсь, это поможет.