Angular 材料日期选择器:日期解析 UTC 问题 1 天前

问题描述 投票:0回答:4

我知道有几个关于此问题的线程,我阅读了所有这些线程,但好几天都无法解决此问题。我可能找到了解决方案,但它似乎对我来说很脏。

与其他用户一样,我对 datePicker 也有同样的问题。对我来说,它是 Angular Material 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);
angular typescript datepicker angular-material utc
4个回答
3
投票

选择和显示的值是相同的...日期时间的不同格式向我们显示了不同的结果(其中日期也发生了变化)!!

例如

  • (默认):2019-06-11T19:00:00.000Z
  • 等于(按 UTCString):2019 年 6 月 11 日星期二 19:00:00 GMT
  • 等于(通过 LocaleString):6/12/2019, 12:00:00 AM
  • 等于(按 LocaleTimeString):12:00:00 AM

我们不需要转换它,因为日期对象包含相同的精确时间。

这个 stackblitz 将进一步显示格式可以在表面上产生的差异,但日期在下面是相同的;如果您有问题/意见,您可以分叉此 stackblitz,进行更改并针对此答案发表评论,我会尽力澄清。

相关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>

3
投票

回应你自己的错误答案

UTC 晚上 11 点 = 00:00+第二天 01:00(同一时刻)

1999 年 12 月 24 日星期三 00:00:00 GMT+0100(欧洲中部正常时间) 但在请求中是

1999-12-23T23:00:00.000Z

这两个字符串代表相同的值。它们是观看同一时刻的两种方式。一个是 UTC 晚上 11 点,另一个比 UTC 早一小时,因此代表第二天的第一个时刻。在 24 小时长的一天中,23 日晚上 11 点加上一个小时就过了午夜钟声,到 24 日的第一刻。

解析

将输入字符串解析为

Instant
。末尾的 Z 表示 UTC,发音为“Zulu”。
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
类。 JDBC 4.2 及更高版本要求 JDBC 驱动程序中支持
OffsetDateTime
类,而
Instant
支持是可选的。

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

通过带有占位符

PreparedStatement
?
写入数据库。

myPreparedStatement.setObject( … , odt ) ;

检索。

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

这在 Stack Overflow 上已经讨论过很多次了。因此搜索以了解更多信息。请在发布之前彻底搜索 Stack Overflow。

LocalDate

如果您的目标只是跟踪日期,并且您并不真正关心时间和时区,那么您应该在 Java 中使用

LocalDate
并在标准 SQL 中使用
DATE
列。


0
投票

最后问题出在我的后端,需要了解发生了什么。

要将日期直接保存到我的 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

-1
投票

哈哈,我的肮脏解决方案是这个方法,它的作用是,因为我只想将日期作为字符串发送回来,没有任何其他信息,它将被映射到后端的日期时间对象,并且已保存...

public setDate(date: any): string {
    const chosenDate = new Date(date);
    return `${chosenDate.getMonth() + 1}/${chosenDate.getDate()}/${chosenDate.getFullYear()}`;
}

然后在html中设置对象值

<mat-form-field appearance="outline">
    <mat-label>Birthdate</mat-label>
    <input matInput [matDatepicker]="birthdatePicker" placeholder="Birthdate" 
        (dateChange)="user.birthdate = setDate($event.value)">
    <mat-datepicker-toggle matSuffix [for]="birthdatePicker"></mat-datepicker-toggle>
    <mat-datepicker #birthdatePicker></mat-datepicker>
    <mat-error>error</mat-error>
</mat-form-field>
© www.soinside.com 2019 - 2024. All rights reserved.