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
Related
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.
Why do I get 2 different dates with new Date() when I pass a date vs. when I pass a date and time?
example:
Date.parse('2015-03-14')
// 1426291200000
new Date(1426291200000)
// Fri Mar 13 2015 17:00:00 GMT-0700 (PDT)
Date.parse('2015-03-14 00:00:00')
// 1426316400000
new Date(1426291400000)
// Fri Mar 13 2015 17:03:20 GMT-0700 (PDT)
Sorry but I cannot comment yet. The string you pass in Date.parse() must follow the
ECMAScript 5 ISO-8601 format support
.Reference link here
format specified in ECMAScript 2015
According to that, you the format of Date with time must be: '2015-03-14T00:00:00' instead of '2015-03-14 00:00:00'.
And since the time of Date.parse('2015-03-14') is at GMT+00 but Date.parse('2015-03-14T00:00:00') is at your time zone so if you add timezone GMT+00 to the second two time will be equal:
Date.parse('2015-03-14');
Date.parse('2015-03-14T00:00:00+00:00');
//1426291200000
Why do I get 2 different dates with new Date() when I pass a date vs. when I pass a date and time?
Because parsing strings with the Date constructor (and Date.parse, they are equivalent) is largely implementation dependent and therefore strongly recommended against.
Date.parse('2015-03-14')
// 1426291200000
new Date(1426291200000)
// Fri Mar 13 2015 17:00:00 GMT-0700 (PDT)
ISO 8601 format dates are treated as UTC in browsers compliant with ES5 and later (and UTC, local or invalid by earlier implementations), however not all browsers are compliant. Also, the specified behaviour is inconsistent with ISO 8601, which specifies that dates without a time zone are to be treated as local.
Date.parse('2015-03-14 00:00:00')
// 1426316400000
new Date(1426291400000)
// Fri Mar 13 2015 17:03:20 GMT-0700 (PDT)
The string '2015-03-14 00:00:00' is not compliant with ISO 8601, therefore parsing is entirely implementation dependent and may be treated as UTC, local or invalid. If made compliant with the addition of a "T":
"2015-03-14T00:00:00"
it should be treated as local (noting the previously mentioned caveat about non–compliant implementations).
It is very strongly recommended that you always manually parse strings. Use a library, one of the many good parsers that are around or just write your own function, 2 or 3 lines should suffice.
I get dates from the database in this format:
yyyy-mm-dd
When I create a javascript Date object using this string, it builds a day before the date.
You can test this in your console:
var d = new Date("2015-02-01");
d
You will get January 31st! I've tested many theories, but none answer the question.
The day is not zero-based, otherwise it would give Feb 00, not Jan 31
It's not performing a math equation, subtracting the day from the month and/or year
Date(2015-02-01) = Wed Dec 31 1969
Date("2015-01") = Wed Dec 31 2014
It is not confusing the day for the month
Date("2015-08-02") = Sat Aug 01 2015
If this were true the date would be Feb 08 2015
If you create a Date using a different format, it works fine
Date("02/01/2015") = Feb 1st, 2015
My conclusion is that js does this purposefully. I have tried researching 'why' but can't find an explanation. Why does js build dates this way, but only with this format? Is there a way around it, or do I have to build the Date, then set it to the next day?
PS: "How to change the format of the date from the db" is not what I'm asking, and that is why I'm not putting any db info here.
Some browsers parse a partial date string as UTC and some as a local time,
so when you read it the localized time may differ from one browser to another
by the time zone offset.
You can force the Date to be UTC and add the local offset if you
want the time to be guaranteed local:
1. set UTC time:
var D= new Date("2015-02-01"+'T00:00:00Z');
2. adjust for local:
D.setMinutes(D.getMinutes()+D.getTimezoneOffset());
value of D: (local Date)
Sun Feb 01 2015 00:00:00 GMT-0500 (Eastern Standard Time)
Offset will be whatever is local time.
Some differences between browsers when time zone is not specified in a parsed string:
(tested on Eastern Standard Time location)
(new Date("2015-02-01T00:00:00")).toUTCString();
Firefox 35: Sun, 01 Feb 2015 05:00:00 GMT
Chrome 40: Sun, 01 Feb 2015 00:00:00 GMT
Opera 27: Sun, 01 Feb 2015 00:00:00 GMT
IE 11: Sun, 01 Feb 2015 05:00:00 GMT
IE and Firefox set the Date as if it was local, Chrome and Opera as if it was UTC.
In javascript, Date objects are internally represented as the number of milliseconds since Jan 1st 1970 00:00:00 UTC. So instead of thinking of it as a "date" in the normal sense, try thinking of a Date object as a "point in time" represented by an integer number (without timezone).
When constructing your Date object using a string, you are actually just calling the parse function. Most date time formats (including ISO 8601) allow you to reduce the precision of a date string.
For reduced precision, any number of values may be dropped from any
of the date and time representations, but in the order from the least
to the most significant.
e.g. 2015-02-01 would represent the day February 1st 2015.
This causes a dilemma for javascript because a Date object is always accurate to the millisecond. Javascript cannot store a reduced accuracy date since it is just an integer of milliseconds since 1st Jan 1970. So it does the next best thing which is to assume a time of midnight (00:00:00) if not specified, and a timezone of UTC if not specified.
All valid javascript implementations should give the same result for this:
var d = new Date("2015-02-01");
alert(d.getTime());
1422748800000
The out-by-1-day issue comes when outputting the date either to some (often unclear) debugger or using the getter methods because the local timezone is used. In a browser, that will be your operating systems timezone. Anyone "west" of Greenwich Mean Time may see this problem because they have a negative UTC offset. Please note there are UTC equivalent functions too which use the UTC timezone, if you are really just interested in representing a date rather than a point in time.
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.
I tested the following code in firefox scratchpad and got interesting result?
var date=new Date("2012-05-12");
var date2 = new Date("05/12/2012");
date;
/*
Fri May 11 2012 17:00:00 GMT-0700 (Pacific Daylight Time)
*/
date2;
/*
Sat May 12 2012 00:00:00 GMT-0700 (Pacific Daylight Time)
*/
Two dates are different. Apparently this is due to the timezone issue. What I want is date2 result. How can I make js engine correctly treats the ISO date style?
I think the issue is that the string "2012-05-12" is taken to be an ISO 8601 date, while "05/12/2012" is an RFC 2822 date. In the ISO format, the lack of a timezone implies UTC. At midnight on the morning off May 12, in California (or wherever you are) it's 7 PM the previous evening.
The RFC date without a time zone, however, is parsed under the assumption that you want the timestamp for midnight in your local timezone. (Well, not necessarily your timezone; the timezone of the computer where your JavaScript runs :-)
You can see the difference if you pass those strings to Date.parse().
The RFC date format can include an explicit time zone, but the ISO format cannot. (Well, it can, but browsers don't pay attention, and apparently IE doesn't handle those at all.)
edit — here's a simple (dumb; no error checking) function that'll give you a date from that 3-part ISO form:
function isoDate( str ) {
var rv = null;
str.replace(/^(\d\d\d\d)-(\d\d)-(\d\d)$/, function(_, yr, mn, dy) {
rv = new Date(parseInt(yr, 10), parseInt(mn, 10) - 1, parseInt(dy, 10));
});
return rv;
}
By the standard, with Date(), you can parse ISO dates or dates in an implementation-dependent format, in an an implementation-dependent manner. To get anything more reliable, use a suitable library that can parse dates in some known formats.