день неправильный в угловом материале datepicker

Когда я выбираю дату, я вижу правильную дату в поле, но, когда я сохраняю, датапикер отправляет день до даты, которую я выбрал (смещение за 3 часа). Я использую угловую реактивную форму и MatMomentDateModule для выбора даты.

проблема связана с часовыми поясами, но я просто хочу сохранить ту же дату, которую пользователь вводит в базу данных.

Код, представленный здесь: https://stackblitz.com/edit/angular-material-moment-adapter-example-kdk9nk?file=app%2Fapp.module.ts

issue on stackblitz

вопрос, связанный с этим по 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 для средства выбора даты, надеюсь, это поможет.