Angular.js: $http modifies date in POSTED JSON object (removes timezone or seasonal offset)

Created on 25 Apr 2016  ·  3Comments  ·  Source: angular/angular.js

I think this is a bug.

What is the current behavior?

Currently I have a nice date object which logs out to

Fri Apr 29 2016 13:33:00 GMT+0100 (BST)

When this object is then POSTED via $http the following is observed in the network requests..

2016-04-28T12:33:00.000Z

So the $http object subtracts an hour and effectively removes the British Summer Time BST from the time. So this is stored in the database without this offset. When we immediately read this date it comes back but how can the system know that we need to add back the hour ?

So imagine also of the user is in another timezone..say 5 hours ahead then the system will subtract 5 hours...Time is sensitive to the context in which it is created. in other words the timezone information should not be removed.

I am seeing this in Chrome. Angular 1.4.2

Also http://stackoverflow.com/questions/24356475/angular-js-date-changes-when-submitting-to-http-timezone-issue

Most helpful comment

First I think it is not correct saying Date object does not have a timezone information.

I still think it is correct to say that :grin: A Date object _"represents a single moment in time [...] based on a time value that is the number of milliseconds since 1 January 1970 UTC"_ (source: MDN). So, basically each Date instance only knows about this one value and all other representations of it are induced based on that info plus locale/system state (such as timezone offset).

#

A Date object has getTimezoneOffset and toISOString methods.

These are methods on the Date prototype (source: MDN), not of the Date objects (aka instances) themselves.

More specifically, the value of getTimezoneOffset() depends on the current locale (host system settings). This is the reason why there is no equivalent setTimezoneOffset() method and why all Date objects on the same system return the same value for getTimezoneOffset(), e.g.:

const d1 = new Date('December 15, 2018 12:34:56');  // No timezone; uses the current system locale.
const d2 = new Date('December 15, 2018 12:34:56 GMT+10'); // Uses GTM+10 as timezone.

d1.getTimezoneOffset() === d2.getTimezoneOffset();  // true

So, the timezone info specified in a date string representation passed to Date is only used to parse that string and map it to a specific moment in time as described above. The resulting Date object does not know anything about timezones :smiley:

The toISOString() method does not print timezone info as you suggested. It just adds Z at the end, which denotes UTC.

#

Secondly, JSON.stringify() also does not strip zone value

As explained above, it uses toISOString(), which expresses the date value in UTC (thus appending Z at the end to indicate that). There is no timezone info in the returned string.

#

So I still believe is that if the API render an ISO date which does not have those milliseconds value and UI is using some datepicker which only picks a date and change date then Angular when sending the date back converting into ISO format it will not have milliseconds value.

I have no idea what milliseconds have to do with it. We were talking about timezone info.

Again, this has nothing to do with AngularJS. This is how the built-in objects (such as Date and JSON) interact with each other.

All 3 comments

This is not something Angular-specific. It is standard JSON.stringify behavior.

Basically, when posting data, $http converts it to JSON (via JSON.stringify()). In JavaScript, the JSON representation of a Date object is its ISO-8601 form (which is what you see in the network tab).

A Date object doesn't have a timezone information anyway, so there is no information stripped. The current locale (which is totally independent of the date represented by Date objects) has a timezone offset and the browser formats the date according to that offset when console.logging it.

Closing as this is not an issue with Angular.

@gkalpak First I think it is not correct saying Date object does not have a timezone information. When we create a date by new Date(), the time zone information is the local zone by default. A Date object has getTimezoneOffset and toISOString methods. When called these methods returns zone value, it is nothing browser is printing nice for us, they are actual values in the Date object.

new Date().getTimezoneOffset()
-330

new Date().toISOString()
"2018-12-04T05:40:37.399Z"

Secondly, JSON.stringify() also does not strip zone value, the following is what we saw in browser console and it is the same, the browser is not printing anything nice for us.

JSON.stringify({d:new Date()})
"{"d":"2018-12-04T05:42:08.973Z"}"

So I still believe is that if the API render an ISO date which does not have those milliseconds value and UI is using some datepicker which only picks a date and change date then Angular when sending the date back converting into ISO format it will not have milliseconds value.

First I think it is not correct saying Date object does not have a timezone information.

I still think it is correct to say that :grin: A Date object _"represents a single moment in time [...] based on a time value that is the number of milliseconds since 1 January 1970 UTC"_ (source: MDN). So, basically each Date instance only knows about this one value and all other representations of it are induced based on that info plus locale/system state (such as timezone offset).

#

A Date object has getTimezoneOffset and toISOString methods.

These are methods on the Date prototype (source: MDN), not of the Date objects (aka instances) themselves.

More specifically, the value of getTimezoneOffset() depends on the current locale (host system settings). This is the reason why there is no equivalent setTimezoneOffset() method and why all Date objects on the same system return the same value for getTimezoneOffset(), e.g.:

const d1 = new Date('December 15, 2018 12:34:56');  // No timezone; uses the current system locale.
const d2 = new Date('December 15, 2018 12:34:56 GMT+10'); // Uses GTM+10 as timezone.

d1.getTimezoneOffset() === d2.getTimezoneOffset();  // true

So, the timezone info specified in a date string representation passed to Date is only used to parse that string and map it to a specific moment in time as described above. The resulting Date object does not know anything about timezones :smiley:

The toISOString() method does not print timezone info as you suggested. It just adds Z at the end, which denotes UTC.

#

Secondly, JSON.stringify() also does not strip zone value

As explained above, it uses toISOString(), which expresses the date value in UTC (thus appending Z at the end to indicate that). There is no timezone info in the returned string.

#

So I still believe is that if the API render an ISO date which does not have those milliseconds value and UI is using some datepicker which only picks a date and change date then Angular when sending the date back converting into ISO format it will not have milliseconds value.

I have no idea what milliseconds have to do with it. We were talking about timezone info.

Again, this has nothing to do with AngularJS. This is how the built-in objects (such as Date and JSON) interact with each other.

Was this page helpful?
0 / 5 - 0 ratings