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.
Related
How do you correctly intitialize a timezone-independent date (or I guess a date that is fixed to a single timezone across the html side and the JS side) from a html datepicker?
I have the following simple code, which is producing incorrect dates:
function printDate(){
let d = new Date(document.getElementById("date").value)
alert(d)
}
document.getElementById("printDate").addEventListener("click", e => printDate())
<html>
<body>
Print Date: <br><input type="date" id="date"> <button id="printDate">Add</button>
</body>
</html>
But at least on my computer, currently sitting in U.S. mountain time, it produces incorrect dates. I give it today's date (March 9, 2019), and it alerts yesterday's date in the following format: Fri Mar 08 2019 17:00:00 GMT-0700 (MST). How do I make it not do that?
I really just want it to assume that all input and all output are in GMT.
In a <input type="date" /> element, the selected date is displayed in the locale format, but the value property is always returned in yyyy-mm-dd format, as described in the MDN docs.
In other words, when you choose March 9, 2019, you may see 03/09/2019 from the US or 09/03/2019 in other parts of the world, but value is 2019-03-09 regardless of any time zone or localization settings. This is a good thing, as it allows you to work with the selected date in a standard ISO 8601 format, without trying to apply a time.
However, when you parse a date string in that format with the Date object's constructor (or with Date.parse), you run up against a known issue: The date is not treated as local time, but as UTC. This is the opposite of ISO 8601.
This is described in the MDN docs:
Note: parsing of date strings with the Date constructor (and Date.parse, they are equivalent) is strongly discouraged due to browser differences and inconsistencies. Support for RFC 2822 format strings is by convention only. Support for ISO 8601 formats differs in that date-only strings (e.g. "1970-01-01") are treated as UTC, not local.
It's also in the ECMAScript specification (emphasis mine):
... When the time zone offset is absent, date-only forms are interpreted as a UTC time and date-time forms are interpreted as a local time.
There was a debate about this in 2015, but ultimately it was decided that maintaining compatibility with existing behaviors was more important than being ISO 8601 compliant.
Going back to your question, the best thing to do would be to not parse it into a Date object if you don't need one. In other words:
function printDate(){
const d = document.getElementById("date").value;
alert(d);
}
If you really need a Date object, then the easiest option is to parse the value yourself:
function printDate(){
const parts = document.getElementById("date").value.split('-');
const d = new Date(+parts[0], parts[1]-1, +parts[2], 12);
alert(d);
}
Note the ,12 at the end sets the time to noon instead of midnight. This is optional, but it avoids situations of getting the wrong day when midnight doesn't exist in the local time zone where DST transitions at midnight (Brazil, Cuba, etc.).
Then there's your last comment:
I really just want it to assume that all input and all output are in GMT.
That's a bit different than what you showed. If really that's what you want, then you can construct the Date object as you previously did, and use .toISOString(), .toGMTString(), or .toLocaleString(undefined, {timeZone: 'UTC'})
function printDate(){
const d = new Date(document.getElementById("date").value); // will treat input as UTC
// will output as UTC in ISO 8601 format
alert(d.toISOString());
// will output as UTC in an implementation dependent format
alert(d.toGMTString());
// will output as UTC in a locale specific format
alert(d.toLocaleString(undefined, {timeZone: 'UTC'}));
}
I have div in which I am providing date and time like this
<div class="timing">
<div id="count-down" data-date="2016-08-31 14:21:00"> </div>
</div>
How would I match or compare with current date, because I am getting current date in this format Wed Aug 31 2016 14:34:58 GMT+0500 (Pakistan Standard Time)
I want to redirect a page to new location if current date is greater than provided date
var currentDate = new Date();
var providedDate = $('#count-down').attr('data-date')
if (currentDate.getDate().toString > providedDate)
{
window.location.href = 'Promo';
$('.timing').css("display", "none");
$('.website-loading').css("display", "block");
}
I have div in which I am providing date and time like this
<div id="count-down" data-date="2016-08-31 14:21:00"> </div>
The string in the data- attribute is not consistent with the format specified in ECMA-262 (the "T" separator between the date and time is missing), so you should manually parse it by either writing a parsing function or use a library and provide the format to parse.
If you use the Date constructor (or Date.parse, they are equivalent for parsing) to parse the string, you may get an invalid date (e.g. in Safari, new Date('2016-01-01 12:00:00') produces an invalid date) since parsing of non–standard strings is entirely implementation dependent.
There are many suitable libraries, some suggestions:
moment.js does parsing, formatting, timezones and arithmetic and has a CDN
fecha.js just does parsing and formatting is very much smaller than moment.js
When you create a Date object, it only has one internal value (called its time value), which is milliseconds since 1970-01-01T00:00:00Z (the javascript epoch, which is the same as the UNIX epoch). When you call the toString method, the result is an implementation dependent string that differs between implementations (in your case you see something like "Wed Aug 31 2016 14:34:58 GMT+0500 (Pakistan Standard Time)", a different implementation may produce something else.
How would I match or compare with current date, because I am getting
current date in this format Wed Aug 31 2016 14:34:58 GMT+0500 (Pakistan Standard Time)
When comparing dates, you really just want to compare the time value. If you compare using the relational operators > or <, they will coerce the dates to their time value so you can compare the dates directly, e.g.:
var providedDate = fecha.parse($('#count-down').attr('data-date'), 'YYYY-MM-DD HH:mm:ss');
if (Date.now() > providedDate) {
// providedDate is in the past
}
Note that since no time zone information is provided in the string to parse, it's treated as a "local" date and time and the host system's current settings are used to determine the offset from UTC, which is then used when calculating the time value. The same system works in reverse when generating a local date and time string from the Date using the default toString method.
Also:
currentDate.getDate()
just returns the date (i.e. the day in the month) as a number without the year and month.
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)
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)
What's going on here:
> new Date('Apr 15 2013');
Mon Apr 15 2013 00:00:00 GMT+0100 (GMT Daylight Time)
> new Date('04/15/2013');
Mon Apr 15 2013 00:00:00 GMT+0100 (GMT Daylight Time)
> new Date('2013-04-15');
Mon Apr 15 2013 01:00:00 GMT+0100 (GMT Daylight Time)
Obviously, one is being interpreted as UTC time, while the other two are being interpreted as local time. What causes the difference in parsing?
From the specification:
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. The function first attempts to parse the format of the String according to the rules called out in Date Time String Format (15.9.1.15). If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats.
Of all the formats you provided, only '2013-04-15' is officially supported, so the others seem to fall back to implementation-dependent behavior.
Your third example is the only one that is actually explained by the spec. When you call the Date constructor with a single argument, this is what happens (where v is the string passed to the constructor):
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.
The parse method will attempt to parse the string (emphasis added):
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. The function first attempts to parse the format of the String according to the rules called out in Date Time String Format (15.9.1.15).
If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats.
And the "Date Time String Format" is YYYY-MM-DDTHH:mm:ss.sssZ, and also defines a shorter version of the form YYYY-MM-DD, which is what you use in your third example.
For the other examples, the parse will fail and the behaviour is implementation-defined.
The Date constructor delegates to Date.parse, and it appears that Date.parse has two variants:
Given a string representing a time, parse returns the time value. It
accepts the RFC2822 / IETF date syntax (RFC2822 Section 3.3), e.g.
"Mon, 25 Dec 1995 13:30:00 GMT". It understands the continental US
time-zone abbreviations, but for general use, use a time-zone offset,
for example, "Mon, 25 Dec 1995 13:30:00 GMT+0430" (4 hours, 30 minutes
east of the Greenwich meridian). If you do not specify a time zone,
the local time zone is assumed. GMT and UTC are considered equivalent.
Alternatively, the date/time string may be in
ISO 8601 format. Starting with JavaScript 1.8.5 (Firefox 4), a subset
of ISO 8601 is supported. For example, "2011-10-10" (just date) or
"2011-10-10T14:48:00 (date and time) can be passed and parsed.
Clearly, these behave differently with respect to local timezones
Edit: Looks like this is implementation defined