Выбор даты для углового материала: проблема с датой разбора UTC за 1 день до - PullRequest
2 голосов
/ 13 июня 2019

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

Так что, как и у других пользователей, у меня та же проблема с датой выбора. Для меня это угловой материал Datepicker mat-datepicker

Когда я записываю значение, я получаю правильный результат:

Wed Dec 24 1999 00:00:00 GMT+0100 (Mitteleuropäische Normalzeit)

но в запросе это

1999-12-23T23:00:00.000Z

Что я пробовал еще:

Я добавил { provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } } к своему component и к своему app.module.ts. Это не имеет никакого значения для меня.

Мое грязное решение (перед отправкой запроса):

 let newDate= new Date(this.personalForm.get("dateOfBirth").value);
 newDate.setMinutes(newDate.getMinutes() - newDate.getTimezoneOffset());

Когда я делаю это, консоль регистрирует:

Wed Dec 24 1999 01:00:00 GMT+0100 (Mitteleuropäische Normalzeit)

и запрос правильный:

1997-12-24T00:00:00.000Z

Но если кто-то сейчас будет из другого часового пояса, например GMT-0100, это снова не будет работать. Как это исправить правильно?

Я также динамически меняю адаптер, если необходимо знать:

 this._adapter.setLocale(this.translateService.currentLang);

Ответы [ 3 ]

2 голосов
/ 13 июня 2019

Значение, которое выбирается и отображается одинаково ... это разные форматы даты и времени, которые показывают нам другой результат (где также изменяется дата) !!

Например, :

  • (по умолчанию): 2019-06-11T19: 00: 00.000Z
  • равно (по UTCString): вт, 11 июня 2019 19:00:00 GMT
  • равно (by LocaleString): 12.06.2009, 12:00:00
  • равно (by LocaleTimeString): 12:00:00 AM

Нам не нужно конвертировать его, потому что объект даты содержит одинаковое точное время.

Этот стековый блик дополнительно покажет разницу, которую формат может иметь на поверхности, но дата под ним такая же; Если у вас есть вопросы / комментарии, вы можете раскошелиться на этот стек, внести изменения и опубликовать комментарий к этому ответу, я постараюсь уточнить.

релевантно TS :

import {Component} from '@angular/core';

/** @title Basic datepicker */
@Component({
  selector: 'datepicker-overview-example',
  templateUrl: 'datepicker-overview-example.html',
  styleUrls: ['datepicker-overview-example.css'],
})
export class DatepickerOverviewExample {
  planModel: any = {start_time: new Date() };
  constructor(){}

  dateChanged(evt){
    let selectedDate = new Date(evt);
    console.log("by default:", selectedDate);
    console.log("by UTCString:", selectedDate.toUTCString());
    console.log("by LocaleString:", selectedDate.toLocaleString());
    console.log("by LocaleTimeString:", selectedDate.toLocaleTimeString());
  }

}

релевантно HTML :

<mat-form-field>
  <input matInput [matDatepicker]="picker" placeholder="Choose a date"
  [(ngModel)]="planModel.start_time"
  (ngModelChange)='dateChanged($event)'
  >
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <mat-datepicker #picker></mat-datepicker>
</mat-form-field>

<hr/>

<p>By default: {{planModel.start_time}} </p>
<p>Medium date: {{planModel.start_time | date:'medium'}} </p>
<p>Short date: {{planModel.start_time | date:'short'}} </p>
<p>Short time: {{planModel.start_time | date: 'shortTime' }} </p>
<p>Medium time: {{planModel.start_time | date: 'mediumTime' }} </p>
<p>Long time: {{planModel.start_time | date: 'longTime' }} </p>
<p>Full time: {{planModel.start_time | date: 'fullTime' }} </p>
0 голосов
/ 14 июня 2019

В ответ на свой неправильный ответ

23:00 UTC = 00:00 + 01:00 следующего дня (в тот же момент)

Ср 24 декабря 1999 00:00:00 GMT + 0100 (Mitteleuropäische Normalzeit) но в запросе это

1999-12-23T23: 00: 00.000Z

Эти две строки представляют одно и то же значение. Это два способа просмотра одного и того же момента. Один в 23:00 по UTC, другой на час впереди UTC, поэтому он представляет собой первый момент следующего дня. Добавление одного часа к 23:00 23-го числа в течение 24-часового дня завершает удар полуночи до первого момента 24-го.

Синтаксический

Разобрать вашу входную строку как Instant. Z на конце означает UTC и произносится как «зулу». Instant представляет момент в UTC, всегда UTC, по определению.

Ваша входная строка в стандартном формате ISO 8601. Классы java.time по умолчанию используют эти стандартные форматы при разборе / генерации строк. Поэтому нет необходимости указывать шаблон форматирования.

Instant instant = Instant.parse( "1999-12-23T23:00:00.000Z" ) ;

Момент (дата, время суток и назначенный часовой пояс или смещение от UTC) должны быть сохранены в столбце базы данных типа, подобного стандартному типу SQL TIMESTAMP WITH TIME ZONE. Столбец типа сродни TIMESTAMP WITHOUT TIME ZONE будет иметь тип данных неправильный .

Для записи в вашу базу данных нам нужно переключиться с базового класса строительных блоков Instant на более гибкий OffsetDateTime класс. Поддержка класса OffsetDateTime в драйверах JDBC требуется для JDBC 4.2 и более поздних версий, тогда как поддержка Instant является необязательной.

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ; 

Запись в базу данных через PreparedStatement с заполнителем ?.

myPreparedStatement.setObject( … , odt ) ;

индексирование.

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

Об этом много раз говорилось о переполнении стека. Так что ищите, чтобы узнать больше. И, прежде чем публиковать, внимательно изучите переполнение стека.

LocalDate

Если ваша цель состоит в том, чтобы отслеживать только дату, и вы не заботитесь о времени суток и часовом поясе, вы должны использовать LocalDate в Java и столбец DATE в стандартном SQL.

0 голосов
/ 13 июня 2019

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

Чтобы сохранить дату прямо в моей базе данных Postgres:

     DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
     LocalDateTime lu = LocalDateTime.parse(lastUpdated, inputFormatter);
     LocalDateTime dob = LocalDateTime.parse(dateOfBirth, inputFormatter);

     this.dateOfBirth = Date.from(dob.atZone(ZoneOffset.UTC).toInstant());
     this.lastUpdated = Date.from(lu.atZone(ZoneOffset.UTC).toInstant());

До того, как у меня было

 this.dateOfBirth = Date.from(dob.atZone(ZoneId.systemDefault()).toInstant()); 

что было не так. Я просто получаю запрос, как будто он отправлен Angular, а Java сохраняет его прямо в базе данных.

1999-12-23T23:00:00.000Z 

превращается в

1997-12-24 00:00:00
...