Issue with Angular Material date picker: Date Parsing UTC causing dates to display as one day earlier

After exploring numerous threads related to this issue and spending several days trying to find a solution, I may have stumbled upon a potential fix. However, the workaround feels too messy for my liking.

Similar to other users, I am encountering an issue with the Angular Material Datepicker, specifically mat-datepicker.

When I log the date value, it displays correctly as:

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

But in the request payload, it appears as:

1999-12-23T23:00:00.000Z

My attempts so far include adding

{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } }
to both my component and app.module.ts, but this has not resolved the issue.

As a temporary fix (before sending the request), I have implemented the following workaround:

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

After making this adjustment, the console now logs:

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

And the request payload is now correct:

1997-12-24T00:00:00.000Z

However, this solution may not work for individuals in different time zones such as GMT-0100. How can this issue be rectified properly?

It is worth noting that I also dynamically change the adapter if needed, as shown below:

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

Answer №1

Although the value displayed remains the same, it is the different date-time formats that give us distinct results, altering the appearance of the date itself!

For example:

  • (by default): 2019-06-11T19:00:00.000Z
  • is equivalent to (by UTCString): Tue, 11 Jun 2019 19:00:00 GMT
  • is equivalent to (by LocaleString): 6/12/2019, 12:00:00 AM
  • is equivalent to (by LocaleTimeString): 12:00:00 AM

There is no need for conversion, as the date object retains the exact time.

This stackblitz beautifully illustrates how a format can change the presentation while the date remains constant; Feel free to fork this stackblitz, make modifications, and leave a comment under this answer for any further queries.

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>

Answer №2

Responding to an inaccurate response you provided…

11 PM UTC = 00:00+01:00 the next day (simultaneous)

On Wed, Dec 24, 1999, at 00:00:00 GMT+0100 (Central European Time) whereas in the request it is shown as

1999-12-23T23:00:00.000Z

These two representations signify the same point in time but viewed differently. One denotes 11 PM in UTC, while the other is one hour ahead of UTC, thus representing the initial moment of the following day. Transitioning from 11 PM on the 23rd to 00:00 on the 24th spans across midnight.

Interpreting

Interpret your input string as an Instant. The "Z" denotes UTC and is articulated as "Zulu". An Instant represents a moment in UTC, always being UTC by definition.

Your input string follows the standard ISO 8601 format. The java.time classes automatically utilize these standard formats for parsing/generating strings. Hence, there is no need to specify a format pattern.

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

A moment (consisting of a date, time-of-day, and an assigned time zone or offset-from-UTC) must be stored in a database column of a type similar to the standard-SQL type TIMESTAMP WITH TIME ZONE. Using a column type resembling TIMESTAMP WITHOUT TIME ZONE would be incorrect.

For database writes, transition from the basic building-block class of Instant to the more versatile OffsetDateTime class. JDBC drivers require support for the OffsetDateTime class in JDBC 4.2 and later versions, while support for Instant is optional.

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

For writing to the database using a PreparedStatement, utilize a placeholder ?.

myPreparedStatement.setObject( … , odt ) ;

Retrieval.

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

This topic has been extensively covered on Stack Overflow. It is advised to search and explore further before posting.

LocalDate

If your objective is to solely track a date without considering time-of-day or time zone, employ LocalDate in Java and a DATE column in standard SQL.

Answer №3

After investigating, I discovered that the issue lay within my backend and required a deeper understanding to resolve.

In order to properly store the date in 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());

Prior to this, I had:

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

which was incorrect. I decided to handle the request as provided by Angular, allowing Java to correctly store it in the database.

1999-12-23T23:00:00.000Z 

is transformed into

1997-12-24 00:00:00

Answer №4

My clever workaround for this issue involved creating a simple method that converts the date to a string without any additional information. This string is then mapped to a datetime object in the backend and saved.

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

After formatting the date, I simply 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 = formatDate($event.value)">
    <mat-datepicker-toggle matSuffix [for]="birthdatePicker"></mat-datepicker-toggle>
    <mat-datepicker #birthdatePicker></mat-datepicker>
    <mat-error>error</mat-error>
</mat-form-field>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide to starting the Angular 2 server within ASP.NET MVC

As a newcomer to Angular 2, I am following the quickstart tutorial step by step which can be found here: this In my learning process, I have come across the concept of starting the server when using Angular 2 with the following command: npm start This a ...

Tips for passing an object to a child control

This question is related to Angular 2 development. Link to the article I am trying to call a service, create objects, and pass them to child components through injection without using binding. How can I achieve this? In the sample code provided below (wh ...

Calling GraphQL mutations in ReactPGA

I encountered a 400 Error when making a call from the client to server, and I'm not sure where to start troubleshooting. Oddly enough, when I only include the "id" parameter in the request, everything works fine. However, as soon as I add the additio ...

Modifying the default value setting in MUI Datepicker

Currently, I am utilizing version @mui/x-date-pickers ^6.17.0. Here is the custom date picker I am using: https://i.stack.imgur.com/k8nF1.png Upon clicking the input field, the placeholder switches and a value gets appended. However, modifying the input ...

In the absence of localstorage, what alternatives do we have for storing values?

I need a solution to store my value without using local storage, as the value can be visible in the developer tools with local storage. Is there a method to store a value that is hidden from the developer tools? Any guidance would be appreciated. Thank yo ...

How can time duration be accurately represented in TypeScript?

As I work on designing an interface for my personal project, I am in need of adding a field that represents the length of time taken to complete a task. What data type and format should I use in TypeScript to express this? Below is the interface I have cr ...

Problem with Infragistics radio button not firing change event when value is set manually

After migrating from Angular 11 to 17, I encountered a strange issue with my application's Infragistics radio button. The change event for the radio button does not trigger manually for the first time, but it works fine when changed through the applic ...

Am I utilizing Angular's signals correctly? And what is the purpose of still requiring ChangeDetectorRef.detectChanges()?

I have been experimenting with signals and I am questioning whether the current use case would be more beneficial without using Signals and instead just having a "normal" class member swiper?: Swiper: @Component({ selector: '[app-test]', stan ...

Tips for validating and narrowing a type in TypeScript using isNull instead of isNonNullable

I want to implement a universal type guard for entities returned from an API. The goal is to handle any null | undefined values by throwing an HttpStatus.NOT_FOUND error. Initially, I tried the following approach: export const entityOr404 = <T>(entit ...

Check out the computed typescript types

In my work with TypeScript types, I find myself frequently using Omit, Pick, and similar tools based on other types. While it generally gets the job done, I often struggle with readability when dealing with complex type manipulations. I am interested in f ...

What is the best approach for managing multiple post requests in Angular?

Currently, in my Angular 12 and NestJS project, I am facing a challenge where I need to synchronize approximately 3000 items from an external API into my application's database. However, during the process of submitting the request, I encounter variou ...

Generating a fresh instance of input value in Angular2

In the hierarchy of components, I have a grand parent component where I am passing the "selectedValue" to the parent component like so: @Component({ selector: 'grand-parent', template: '<parent [details]="selectedValue" ></par ...

Creating a button that displays the current day with Angular

I'm in the process of developing a timetable app that features buttons for the previous day, current day, and next day. How can I implement a button to specifically show the current day? HTML File <button type="button" (click)="previousDay()" ...

Focusing on an input element in Angular2+

How do I set focus on an input element? Not with AngularDart, but similar to the approach shown in this question: <input type="text" [(ngModel)]="title" [focus] /> //or <input type="text" [(ngModel)]="title" autofocus /> Does Angular2 provi ...

Can TypeScript automatically deduce keys from a changing object structure?

My goal here is to implement intellisense/autocomplete for an object created from an array, similar to an Action Creator for Redux. The array consists of strings (string[]) that can be transformed into an object with a specific shape { [string]: string }. ...

Guide on invoking an HTML event method from a parent component to a child component

I have the following parent component: JS import { Component, OnInit } from '@angular/core'; import { TaskService } from '../task.service'; import { ViewChild } from '@angular/core/src/metadata/di'; import { CreateNewTaskCom ...

How to temporarily modify/add CSS class in Angular 2

In my Angular 2 application, there is a label that displays the current amount of points for the user. Whenever the number of points changes, I want to briefly change the class of the label to create an animation effect that notifies the user of the chang ...

Restrict the number of subscriptions allowed for an rxjs observable

Seeking a replacement for observable, subject, or event emitter that allows only one subscription at a time. The first subscriber should have priority to execute its subscribe function, with subsequent subscribers waiting their turn until the first unsubsc ...

How can one point to a parameter within the documentation of a TypeScript function?

I am attempting to incorporate parameter references in function descriptions like this: /** * Deletes the Travel Cost with the given {@param id} * @param id the id of the travel cost to be deleted */ deleteTravelCost(id: number): Observable<{}> { ...

I am having trouble setting a component to show up as inline-block in Angular2

Within my Angular2 application, I am facing an issue with displaying multiple instances of a child component - app-video-container - in a grid layout using inline-block. The parent component generates these instances using an ngFor loop but they appear sta ...