问题
I know there are several threads about this and i read them all but couldn't fix this for days. I might found a solution but it seems to be do dirty for me.
So as other users I have the same problem with the datePicker. For me it's the Angular Material Datepicker mat-datepicker
When I log the value I get the correct result:
Wed Dec 24 1999 00:00:00 GMT+0100 (Mitteleuropäische Normalzeit)
but in the request it is
1999-12-23T23:00:00.000Z
What I tried yet:
I've added { provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }
to my component
and to my app.module.ts
. That does not make any difference for me.
My dirty solution (before sending the request):
let newDate= new Date(this.personalForm.get("dateOfBirth").value);
newDate.setMinutes(newDate.getMinutes() - newDate.getTimezoneOffset());
When I am doing this the console logs:
Wed Dec 24 1999 01:00:00 GMT+0100 (Mitteleuropäische Normalzeit)
and the request is right:
1997-12-24T00:00:00.000Z
But if somebody now would be from a different timezone like GMT-0100 this would again not work. How to fix this correctly?
I also change the adapter dynamically if it's necessary to know:
this._adapter.setLocale(this.translateService.currentLang);
回答1:
The value which is picked and displayed is the same... it is the different formats of the date-time which show us a different result (where the date also changes)!!
For e.g:
- (by default): 2019-06-11T19:00:00.000Z
- is equal to (by UTCString): Tue, 11 Jun 2019 19:00:00 GMT
- is equal to (by LocaleString): 6/12/2019, 12:00:00 AM
- is equal to (by LocaleTimeString): 12:00:00 AM
We don't need to convert it, because the date object contains the same exact time.
This stackblitz will further show the difference a format can make on the surface but the date is the same underneath; If you have questions/comments, you can fork this stackblitz, make changes and post a comment against this answer, i'll try to clarify.
relevant 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());
}
}
relevant 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>
回答2:
At the end the problem was in my backend and needed to understand what is going on.
To save the Date right into my Postgres Database:
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());
Before I had
this.dateOfBirth = Date.from(dob.atZone(ZoneId.systemDefault()).toInstant());
which was wrong. I just receive the request like it's given by Angular and Java saves it right into the database.
1999-12-23T23:00:00.000Z
turns into
1997-12-24 00:00:00
回答3:
In response to your own incorrect Answer…
11 PM UTC = 00:00+01:00 the next day (same moment)
Wed Dec 24 1999 00:00:00 GMT+0100 (Mitteleuropäische Normalzeit) but in the request it is
1999-12-23T23:00:00.000Z
These two strings represent the same value. They are two ways of viewing the same moment. One is 11 PM at UTC, the other is an hour ahead of UTC, so it represents the first moment of the next day. Adding one hour to 11 PM on the 23rd in a 24-hour long day takes past the stroke of midnight, to the first moment of the 24th.
Parsing
Parse your input string as an Instant
. The Z on the end means UTC and is pronounced “Zulu”. An Instant
represent a moment in UTC, always UTC, by definition.
Your input string is in standard ISO 8601 format. The java.time classes use these standard formats by default when parsing/generating strings. So no need to specify a formatting pattern.
Instant instant = Instant.parse( "1999-12-23T23:00:00.000Z" ) ;
A moment (a date, a time-of-day, and an assigned time zone or offset-from-UTC) must be saved into a database column of a type akin to the standard-SQL type TIMESTAMP WITH TIME ZONE
. A column of a type akin to TIMESTAMP WITHOUT TIME ZONE
would be the wrong data type.
To write to your database, we need to switch from the basic building-block class of Instant
to the more flexible OffsetDateTime
class. Support for the OffsetDateTime
class in JDBC drivers is required by JDBC 4.2 and later, while Instant
support is optional.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
Write to database via a PreparedStatement
with a placeholder ?
.
myPreparedStatement.setObject( … , odt ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
This has been discussed many many times on Stack Overflow. So search to learn more. And please search Stack Overflow thoroughly before posting.
LocalDate
If your goal is to track just a date, and you don’t really care about time-of-day and time zone, you should be using LocalDate
in Java and DATE
column in standard SQL.
回答4:
Haha, my dirty solution for this was this method, which does it's job for what it is, since I just wanted to send the date back as a string without any other information, which would be mapped to a datetime object in the backend and saved...
public setDate(date: any): string {
const chosenDate = new Date(date);
return `${chosenDate.getMonth() + 1}/${chosenDate.getDate()}/${chosenDate.getFullYear()}`;
}
and then set the object value in the 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>
来源:https://stackoverflow.com/questions/56578738/angular-material-date-picker-date-parsing-utc-problem-1-day-before