角材料日期选择器:日期解析UTC前1天

时间:2019-06-13 10:44:22

标签: angular typescript datepicker angular-material utc

我知道有关此的一些主题,我读了所有这些主题,但是好几天都无法解决。我可能找到了解决方案,但对我来说似乎很肮脏。

因此,与其他用户一样,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 } }添加到了componentapp.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);

4 个答案:

答案 0 :(得分:2)

选取并显示的值是相同的...它是日期时间的不同格式,向我们显示了不同的结果(日期也会更改)!

例如

  
      
  • (默认):2019-06-11T19:00:00.000Z
  •   
  • 等于(by UTCString):Tue,11 Jun 2019 19:00:00 GMT
  •   
  • 等于(通过LocaleString):6/12/2019,12:00:00 AM
  •   
  • 等于(通过LocaleTimeString):12:00:00 AM
  •   

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

This 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>

答案 1 :(得分: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

答案 2 :(得分:0)

响应your own incorrect Answer

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

  

1999年12月24日星期三00:00:00 GMT + 0100(MitteleuropäischeNormalzeit)   但在请求中是

     

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。

LocalDate

如果您的目标只是跟踪日期,并且您并不真正在意时间和时区,则应在Java中使用LocalDate,在标准中使用DATE列SQL。

答案 3 :(得分:0)

哈哈,我对此方法的肮脏解决方案就是这种方法,它的用途是正确的,因为我只想将日期以字符串形式发送回而没有任何其他信息,该信息将映射到后端并保存...

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>