Смещение часового пояса ngx-bootstrap timepicker, из-за которого SQL сохраняет неправильное время

Использование модуля timepicker со всеми параметрами по умолчанию, кроме минутного шага, установленного на 1.

строка кода выглядит следующим образом

let DailyStartTime =  this.dailyStartTime != null ? 
                         new Date(this.dailyStartTime.getFullYear(),
                               this.dailyStartTime.getMonth(),
                               this.dailyStartTime.getDate(),
                               this.dailyStartTime.getHours(),
                               this.dailyStartTime.getMinutes()) : null

записывает данные по состоянию на среду, 31 мая 2017 г., 19:51:00 GMT-0400 (восточное летнее время).

который отображается изначально, но после сохранения обратно в SQL он преобразуется в «2017-05-31T23:51:00», который продвигается по смещению времени. Как я могу отрицать это?


person C Anderson    schedule 01.06.2017    source источник
comment
Удалось ли вам решить эту проблему? Я также сталкиваюсь с той же проблемой. После выбора времени он дает мне дату в формате GMT, что в конечном итоге добавляет 4 часа каждый раз, когда я сохраняю.   -  person HereToLearn_    schedule 08.08.2017


Ответы (2)


У меня была такая же проблема при попытке сохранить реактивную форму с помощью средства выбора времени ngx-bootstrap (3.0) в POST (C # WebApi с EntityFramework)

Похоже на проблему с UTC и локальным компьютером. Дата из средства выбора даты выглядит нормально, но при создании javascript-объекта POST, похоже, настраивается разница в часовом поясе между UTC и локальным компьютером.

Временное решение (.ts):

submit() {
  this.dataService.saveOpenHours({ OpensAt: this.fixDate(this.form.value.openHour), ClosesAt: this.fixDate(this.form.value.closeHour) }).subscribe(data => {
    // do something
  });
}

fixDate(d: Date): Date {
  d.setHours(d.getHours() - d.getTimezoneOffset() / 60);
  return d;
}

HTML

<form id="ngForm" [formGroup]="form" (ngSubmit)="submit()">
  <timepicker formControlName="openHour"></timepicker>
  <timepicker formControlName="closeHour"></timepicker>
</form>

Надеюсь, это поможет кому-то!

person Marius    schedule 14.06.2018

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

Я использую Angular 7 для внешнего интерфейса и .Net Core Web API для внутреннего интерфейса.

Веб-API возвращает дату и время в полезной нагрузке JSON клиенту в виде строк в следующем формате:

2020-04-23T01:00:00

Объектная модель TypeScript/JavaScript сохраняет тип данных строки даты как строковый тип.

Когда bsDatepicker и timepicker подключены в соответствии с приведенным ниже примером кода (в данном случае с использованием двухсторонней привязки модели), тип строки даты в модели изменяется со строкового типа на тип даты JavaScript.

<input name="AppliesEndDate{{index}}" type="text" class="form-control form-control-sm" bsDatepicker [(ngModel)]="costCentre.appliesEndDate" [disabled]="costCentre.totalActiveAssignments!==0" />
<timepicker [(ngModel)]="costCentre.appliesEndDate" [showMeridian]="showMeridian" [disabled]="costCentre.totalActiveAssignments!==0" [minuteStep]="1"></timepicker>

Когда модель отправляется обратно на сервер веб-API через HTTP POST или PUT, тип данных Date в объектной модели сериализуется обратно в строку в виде даты в формате UTC, что обозначается суффиксом Z:

2020-04-23T00:00:00.000Z

Из этого можно сделать вывод, что это происходит на стороне клиента и не имеет прямого отношения к Angular. Возможно, это больше связано с тем, как JavaScript преобразует типы Date в строки.

Возьмите эти примеры. Я намеренно выбрал две даты. Один вне британского летнего времени (GMT+0000), а другой внутри британского летнего времени (GMT+0100).

var date1 = new Date('2019-02-01T14:14:00');
var date2 = new Date('2019-05-01T14:14:00');

Пт, 01 февраля 2019 г., 14:14:00 GMT+0000 (время по Гринвичу)

Ср, 01 мая 2019 г., 14:14:00 GMT+0100 (британское летнее время)

Выполнение приведенных ниже операторов для преобразования в строку ISO:

console.log('toISOString ' + date1.toISOString());
console.log('toISOString ' + date2.toISOString());

Дает следующие результаты:

toISOString 2019-02-01T14:14:00.000Z

toISOString 2019-05-01T13:14:00.000Z

Обе даты конвертируются в формат UTC. Обратите внимание, что во втором примере время 13:14, а не 14:14. На самом деле это правильно, так как 05.01.2019 находится внутри BST, то есть по Гринвичу + 0100. Таким образом, истинное UTC на самом деле 13:14.

Это было бы верно для любого другого региона/часового пояса. Дата и время UTC будут рассчитываться на основе локали/региона клиента.

Под прикрытием я считаю, что это то, что происходит на стороне клиента с Angular при отправке модели обратно в полезную нагрузку на сервер. Это просто вызов toISOString.

Вы также получите те же результаты с JSON.stringify, который, как я полагаю, вызывает toISOString под прикрытием.

console.log(JSON.stringify(date1));
console.log(JSON.stringify(date2));

Попробуйте запустить некоторые из этих команд в Chrome Sources › Snippets или другом блокноте JavaScript.

var date1 = new Date('2019-02-01T14:14:00');
var date2 = new Date('2019-05-01T14:14:00');

console.log(date1);
console.log(date2);

console.log(JSON.stringify(date1));
console.log(JSON.stringify(date2));

console.log('toISOString ' + date1.toISOString());
console.log('toISOString ' + date2.toISOString());

console.log('toGMTString ' + date1.toGMTString());
console.log('toGMTString ' + date2.toGMTString());

console.log('toLocaleString ' + date1.toLocaleString());
console.log('toLocaleString ' + date2.toLocaleString());

console.log('toUTCString ' + date1.toUTCString());
console.log('toUTCString ' + date2.toUTCString());

console.log(date1.getTimezoneOffset());
console.log(date2.getTimezoneOffset());

Итак, в заключение мы получаем дату и время UTC от клиента.

Это, безусловно, хорошо и делает локаль/регион даты и времени независимым.

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

Приведенное выше предложение кода на стороне клиента, безусловно, исправляет смещение, но учтите, что данные все равно будут сериализованы обратно клиенту в виде строки даты UTC. Удалив смещение таким образом, вы фактически нарушили дату UTC. На сервере веб-API по-прежнему будет получать суффикс Z, и это будет рассматриваться как дата в формате UTC. Таким образом, вы на самом деле скорректировали смещение даты, но не контекст формата UTC.

fixDate(d: Date): Date {
  d.setHours(d.getHours() - d.getTimezoneOffset() / 60);
  return d;
}

Однако, если вы должны были отправить дату обратно в виде строки (преобразовать ее самостоятельно и удалить суффикс Z) обратно в этот формат:

2020-04-23T01:00:00

Тогда вы не будете подразумевать, что дата была датой UTC.

Принимая во внимание все вышесказанное, я считаю (после нескольких дней изучения этого вопроса) то, что лучше оставить клиенту сериализацию типов Date как UTC. Примите тот факт, что именно так это и работает, и что всегда возвращать строковые даты в формате UTC — это хорошо с точки зрения согласованности.

С точки зрения серверной части (веб-API в моем случае) дата может быть получена как дата UTC и либо сохранена в вашей базе данных/хранилище данных как дата UTC, ИЛИ вы можете преобразовать ее на стороне сервера в любую локаль/регион по вашему выбору. Помните, что UTC не зависит от региона, что хорошо для глобальных приложений.

В моем случае я решил преобразовать входящие даты и время UTC в локальные даты и времени, используя следующий фрагмент кода перед сохранением в нашей базе данных.

o.AppliesStartDate.ToLocalTime();

Я надеюсь, что это поможет кому-то и, надеюсь, прояснит, как все работает. Два дня назад я вообще этого не понял... но теперь это имеет смысл.

Вы также можете делать такие вещи, как в веб-API С#:

TimeZoneInfo ist = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
TimeZoneInfo gmt = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");

var a1 = new DateTime(2019, 5, 30, 12, 30, 30, DateTimeKind.Utc);
Console.WriteLine(TimeZoneInfo.ConvertTimeFromUtc(a1, gmt));
Console.WriteLine(TimeZoneInfo.ConvertTimeFromUtc(a1, ist ));

Это может дополнительно прояснить, что даты принимаются в веб-API как типы дат в формате UTC. Если вы проверите свойство kind на стороне веб-API десериализованной структуры даты и времени, вы увидите UTC.

Я надеюсь, это поможет вам.

person Robin Webb    schedule 02.02.2019