Thursday, September 27, 2018

ASP.NET Core and Angular Ignore TimeZone – Part 1 of 2


Date and Time is always hard, especially when it spans across time zones. Once your application becomes global, the time zone related issues become inevitable. This becomes harder with Single Page Application Technology, now we need to sync date between the javascript running on browser and with that of server.

Have you faced issue where you are losing a day or getting a day more than what user entered in your Angular application? Chances are that your server is in one time zone and your user is in a different time zone. Your user enters the date or picks the date using a calendar control (example Expiration Date). Due to time zone difference, the date may change when it reaches server. For example, user in India picked date at 27-09-2018 at 9:00 AM, the server in California receives this date as 26-09-2018 8:30 PM. If you are considering only date part then your date will be one day less (26th instead of 27th) due to this time zone conversion.

Below are the two solutions for this problem:
  1. Ignore time zone globally when sending data between browser and server
  2. A more elegant solution is to ignore time zone only for specific date controls or properties

In this blog, I will cover the first solution and in my next blog I will go over the second solution.

Ignore time zone globally
In most applications, we do not need to consider time. In these applications, ignoring time zone is the best approach. As you know, Angular and ASP.NET by default convert the date from one time zone to another time zone. This is true even if you are sending just date.

The best way for this problem, is to remove time zones while exchanging data between ASP.NET and Angular. Unfortunately, there is no out of box solution to remove time zones. However, the solution is very easy. When the data is exchanged between ASP.NET and Angular, the data is serialized to JSON and is transferred. We can tap into this serialization process and can force date conversion to ignore time zone.

ASP.NET Core by default uses Json.NET to serialize the data. In Json serialization configuration, we can specify the date serialization to remove time zone. For this, we need to pass the Date format as shown below:

.AddJsonOptions(options =>
{
      options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
      options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
      options.SerializerSettings.DateFormatString = "yyyy-MM-ddTHH:mm:ss";
});
In Angular we also need to override the Json serialization. Angular internally uses Json.stringy to serialize the object. Under hood, this json serializer uses toISOString. We can override this and provide the same format we used in the ASP.NET.


  Date.prototype.toISOString = function() {
      return this.getFullYear() + "-" + this.getMonth().toString().padStart(2, "0")
          + "-" + this.getDate().toString().padStart(2, "0") + "T"
          + this.getHours().toString().padStart(2, "0") + ":"
          + this.getMinutes().toString().padStart(2, 0) + ":"
          + this.getSeconds().toString().padStart(2, 0);
  };
By providing DateFormats without time zone on both ASP.NET and Angular we can ignore time zone. With this approach our application does not lose a day while sending data to and fro.

4 comments:

  1. Sir thanks a lot..i have configured in asp.net core ..where i have to write Date.prototype.toISOString = function() {) function in anguar..This is my service class
    getTransactionById(id: number): Observable {

    return this.httpClient.get>(baseUrl + '/Transaction/GetTransactionById'+ `/${id}`)
    .pipe(map( res => res.data));
    }

    ReplyDelete
    Replies
    1. In App.module.ts constructor. Take a look at:
      https://stackoverflow.com/questions/55064962/override-date-prototype-tojson-for-solving-timezone-problem-in-angular-7

      Delete
  2. Thanks for posting.

    Is the function missing a +1 in the month? Javascript starts the month number with zero, something odd. So, should it be like this?

    (this.getMonth() + 1).toString().padStart(2, "0")

    ReplyDelete
  3. You are totally right!

    ReplyDelete