I am doing some javascript date stuff, and I executed the following:
console.log(new Date(0));
I expected to see the *nix Epoch, but I was oddly returned:
Wed Dec 31 1969 19:00:00 GMT-0500 (Eastern Standard Time)
What happened?
You are setting the internal time value, which is UTC, but seeing a string that is based on your system settings, which likely have an offset of UTC-05:00.
The ECMAScript specification explains how the Date constructor and instances work. Given:
new Date(0)
the Date constructor is called with one argument (§20.3.2.2 Date(value)) so it creates a Date instance with it's internal time value set depending on the type of argument. As the value is a number, the time value is set to that number.
The time value is an offset in milliseconds from 1970-01-01T00:00:00Z §20.3.1.1 Time Values and Time Range. Note that it's based on UTC.
The behaviour of console.log is entirely implementation dependent, so what you get from:
console.log(dateInstance);
depends on the host. However, most seem to call the object's toString method which returns an implementation dependent string based on the timezone setting for the host system (§20.3.4.41 Date.prototype.toString()). That is, a "local" time.
The timezone offset can be determined using getTimezoneOffset. It's in minutes and has the opposite sense to an ISO 8601 offset (e.g. UTC-05:00 will be +300). If you want to get a date string that represents the internal time value without an offset, use toUTCString.
I was unable to find any resources explaining it, but this 'error' is due to my timezone (as far as I can tell)
My timezone is GMT-0500, which is 5 hours behind UTC time. Add 5 hours to Wed Dec 31 1969 19:00:00 and you get the Epoch (Thurs Jan 1 1970 00:00:00)
Related
I have been using momentjs and moment-timezone for a while. While using date comparison using isAfter method today, I discovered strange behaviour.
Suppose one moment date is configured with timezone value and other isn't then what should be the behaviour of date comparison?
In my case, we are converting an epoch time to specific timezone value for one date. Other date is in format yyyy-mm-dd without any timezone value. When I am comparing these two days, it is failing for same day value.
//Wed Sep 27 2017 01:13:04 GMT-0700
var localtime = moment(1506499984924).tz("America/Los_Angeles");
//Wed Sep 27 2017 00:00:00
var date = moment('2017-09-27');
//returns true
var value = localtime.isAfter(date, 'day');
Ideally since both dates are Sept 27 2017, it should return false.
Using diff method instead isAfter returns 0 which is true.
Any help is appreciated to solve this issue.
I have created a pen with this code: Moment
In your code:
var date = moment('2017-09-27');
This create a value at midnight local time. How that relates to a specific instant in time is highly dependent on which local time zone your computer is set to.
Moment objects are always compared as moments - that is, instantaneous values based on UTC.
I see false when I run your code pen because I am in a time zone that is behind UTC. If you see true, it's because you are in a local time zone that is ahead of UTC (by over an hour, given the time of the other value).
I am trying to convert milliseconds into UTC date object as below -
var tempDate = new Date(1465171200000);
// --> tempDate = Mon Jun 06 2016 05:30:00 **GMT+0530 (India Standard Time)** {}
var _utcDate = new Date(tempDate.getUTCFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate(), tempDate.getUTCHours(), tempDate.getUTCMinutes(), tempDate.getUTCSeconds());
//--> _utcDate = Mon Jun 06 2016 00:00:00 **GMT+0530 (India Standard Time)** {}
Time is resetting to UTC time but Time Zone is still coming as GMT+0530 (India Standard Time).
Is there any sure shot approach to convert milliseconds into UTC date object with UTC Time Zone?
Quoting from this answer (that I suggest you to read completely):
There is no time zone or string format stored in the Date object itself. When various functions of the Date object are used, the computer's local time zone is applied to the internal representation.
As time zone is not stored in the Date object there is no way to set it.
I see two options:
the first is to make use of a library (as suggested in the answer above). Quite popular now is Moment.js
the second (pure JavaScript - if it's a viable solution in your context):
Do the "time math" in your local timezone.
When you're ready to switch to UTC use toUTCString() method.
Of course you'll end up with a string as this let you store the time zone as long as the date time value.
As you won't be able to manipulate the date time as a Date object from now on this must be the last step.
var tempDate = new Date(1465171200000);
// Mon Jun 06 2016 05:30:00 GMT+0530
// Do your date time math here
// using the Date object's methods
var utcDateAsString = tempDate.toUTCString();
// Mon Jun 06 2016 00:00:00 GMT
You say:
Time is resetting to UTC time but Time Zone is still coming as GMT+0530 (India Standard Time). Is there any sure shot approach to convert milliseconds into UTC date object with UTC Time Zone?
But I think you misunderstand what is occurring. When you pass a number to the Date constructor as in:
new Date(1465171200000)
is it assumed to be milliseconds since the ECMAScript epoch (1970-01-01T00:00:00Z), so a Date object is created with that value as its internal time value. So Date objects are inherently UTC.
When you write that to a string, internally a human readable date string is generated based on the host timezone setting, which is why you see a date for GMT+0530 (that is your host system timezone setting). The Date object itself does not have a timezone, it's always UTC.
When you then use UTC values to create a "local" Date using:
new Date(tempDate.getUTCFullYear(), tempDate.getUTCMonth(), ...)
then the host timezone is used to generate a UTC time value equivalent to a "local" date for the associated values. You've effectively subtracted your timezone offset from the original time value so it now represents a different moment in time. You can get exactly the same result doing:
var d = new Date(1465171200000);
d.setMinutes(d.getMintues() + d.getTimezoneOffset());
which just shows a bit more clearly what's going on. Note that ECMAScript timezone offsets are in minutes and have the opposite sense to UTC, that is, they are negative (-) for east and positive (+) for west. So an offset of UTC+05:30 it is represented as -330 and you need to add it to "shift" a Date rather than subtract it.
var tempDate = new Date(1465171200000);
var _utcDate = new Date(tempDate.getUTCFullYear(), tempDate.getUTCMonth(), tempDate.getUTCDate(), tempDate.getUTCHours(), tempDate.getUTCMinutes(), tempDate.getUTCSeconds());
console.log('Direct conversion to Date\ntempDate: ' + tempDate.toString());
console.log('Adjusted using UTC methods\n_utcDate: ' + _utcDate.toString());
tempDate.setMinutes(tempDate.getMinutes() + tempDate.getTimezoneOffset());
console.log('Adjusted using timezoneOffset\ntempDate: ' + tempDate.toString());
However, I can't understand why you want to do the above. 1465171200000 represents a specific moment in time (2016-06-06T00:00:00Z), adjusting it for every client timezone means it represents a different moment in time for each client with a different timezone offset.
If you create a Date from a Number, the local timezone is the one considered. But if you want to see what a timestamp would mean with the hours corrected for UTC, you could use a helper as such:
Number.prototype.toUTCDate = function () {
var value = new Date(this);
value.setHours(value.getHours() - (value.getTimezoneOffset() / 60));
return value;
};
The usage would be:
var date = (1465171200000).toUTCDate();
I store two dates. First date is the current day and the second one is a future date. To convert those dates into format year-month-day I use toISOSstring function. However usually (but not always) the current date is changed one day backwards.
I also tried to use toJSON function instead. But nothing has changed.
season.from = "Sun Apr 02 2017 18:29:52 GMT+0200 (CEST)"
season.to = "Fri Apr 21 2017 18:29:52 GMT+0200 (CEST)"
var date1 = new Date(season.from);
var date2 = new Date(season.to);
season.from = date1.toISOString().slice(0,10);
season.to = date2.toISOString().slice(0,10);
console.log(season.from); // one day backwards (e.g. 2017-04-01 not 2017-04-02)
console.log(season.to); // proper date somewhere in the future
Your original time strings are in local time, or at least they have a time zone specification. But toISOString returns the UTC time:
The timezone is always zero UTC offset, as denoted by the suffix "Z"
In the case of your GMT+02 time zone, this means the date/time returned by toISOString is two hours "earlier" than the local time. In some cases this can be a time before midnight, and this can render a different date as well.
The implementation of the toJSON method depends on toISOString, so it has the same behaviour.
Work-around
You could use toLocaleDateString('se'), which uses your local time, and formats according to Swedish standards, i.e. YYYY-MM-DD, so you don't even need to slice it. There are some other country codes you could specify to have the same.
This question already has an answer here:
HTML Input type datetime-local setting the wrong time-zone
(1 answer)
Closed 7 years ago.
I'm writing a MVC 5 web application. Into this, I have multiple lists that I propagate and manage through javascript and jquery (one dataset, dependent select controls, and adding ajax callbacks would complicate it unnecessarily.)
The issue I have is: I have a hidden for field formatted to ISO 8601. I run into issues when I display the date in the user's local time, I get a shifted date.
So if the date were stated as: 01-01-2009 (in iso 8601 format: 2009-01-01), the user sees: 12-31-2008.
When I parse the date I'm using:
this.date = new Date(Date.parse(originalString));
/* ^- Date.parse is giving me a number. */
To display the text of the date I am using:
admin.date.toLocaleDateString().Concat(...
Do I need to do any sort of patch-up to adjust things to the proper time-zone? The date, when using console.log(admin.date); shows the original 2009-01-01
I'm thinking there's some parameter I'm not specifying correctly in the toLocaleDateString, but my familiarity level with it is low.
Edit: The goal is to prevent the date shift. All we store is the date, the time aspect is dropped. We have multiple time-zones posting to this database, and the goal is: We use the date of the person who posted it, time dropped. Were the date May 01, 2015, I want anyone who sees that date to see May 01, 2015, the 'toLocaleDateString' is merely a means to get it to appear format correct for their region. So someone who views dates as yyyy-mm-dd will see it properly.
Based on the documentation for Date.parse:
The Date.parse() method parses a string representation of a date, and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC.
You are getting back the epoch time in UTC for your parsed date string hence why the date is off for local times. So, you would need to know the time difference between the local time and UTC which Date.getTimezoneOffset provides (in minutes) in order to set the correct date for the local time:
> var date = new Date(Date.parse('2009-01-01'));
undefined
> date;
Wed Dec 31 2008 19:00:00 GMT-0500 (EST)
> date.getTimezoneOffset();
300
> date.setMinutes(date.getTimezoneOffset());
1230786000000
> date;
Thu Jan 01 2009 00:00:00 GMT-0500 (EST)
One thing to note though is:
...the offset is positive if the local timezone is behind UTC and negative if it is ahead.
So you might need to take care for locales where the value is negative if this applies to your application. If so maybe just omitting negative values would be enough since the date should be the same if a locale's timezone is ahead of midnight UTC.
EDIT: To compensate for possible issues with daylight savings time:
> var dateVals = String.prototype.split.call('2009-01-01', '-');
undefined
> var date = new Date(dateVals[0], dateVals[1] - 1, dateVals[2]);
undefined
> date
Thu Jan 01 2009 00:00:00 GMT-0500 (EST)
In doing some testing I've found inconsistant behavior between browsers with the following javascript
new Date("2013-09-10T08:00:00").toString()
In IE and Firefox the result is
"Tue Sep 10 2013 08:00:00 GMT-0400 (Eastern Daylight Time)"
In Chrome the result is
"Tue Sep 10 2013 04:00:00 GMT-0400 (Eastern Daylight Time)"
So according to my reading of the ECMA script of the format for Date strings it says...
All numbers must be base 10. If the MM or DD fields are absent "01" is
used as the value. If the HH, mm, or ss fields are absent "00" is
used as the value and the value of an absent sss field is "000".
The value of an absent time zone offset is "Z"
However in the documentation for the "new Date()" constructor it says
15.9.3.2 new Date (value)
Let v be ToPrimitive(value).
If Type(v) is String, then
a. Parse v as a date, in exactly the same manner as for the parse method (15.9.4.2); let V be the time
value for this date.
15.9.4.2 Date.parse (string)
The parse function applies the ToString operator to its argument and interprets the resulting String as a date
and time; it returns a Number, the UTC time value corresponding to the
date and time. The String may be interpreted as a local time, a UTC
time, or a time in some other time zone, depending on the contents of
the String.
Any ideas which implementation is correct?
Standards clash. ISO 8601 states that:
If no UTC relation information is given with a time representation, the time is assumed to be in local time.
ECMA says:
The value of an absent time zone offset is “Z”.
Mozilla devs think that ISO takes precedence, Chrome folks seem to disagree.
The current draft of ES6 says (under 20.3.1.15):
If the time zone offset is absent, the date-time is interpreted as a local time.
so Mozilla's implementation is (will be) correct.
There are several questions on stackoverflow.com that address this issue. I gave a rather thorough explanation here if anyone reading this is interested in the browser-to-browser details.
The bottom line though is, for now at least, you should either avoid the ISO 8601 format all together or ALWAYS include a timezone specifier when using it. And, never use the 'YYYY-MM-dd' format because it gets interpreted as a short version of ISO 8601 without a time zone specifier.