new Date() producing valid date from invalid input string [duplicate] - javascript

This question already has answers here:
Detecting an "invalid date" Date instance in JavaScript
(52 answers)
Closed 3 years ago.
When I pass "test 2" string in new Date(), I am getting an actual date, how?
I am trying to whether it is a date or not.
console.log(new Date("test 2"));

Passing a string to new Date is the same as using Date.parse.
When a non-standard date string is passed, the result is implementation-dependent; the browser can do whatever it wants, including guessing. On Chrome, your input results in a date, but not on Firefox (NaN is returned).
test isn't part of a date string, so it looks like Chrome just parses the 2:
console.log(new Date('2'));
console.log(new Date('1'));
console.log(new Date('0'));
Essentially, this is undefined behavior, so strange results aren't surprising. Unless the passed string conforms to the format defined in the specification - that is, something like "2011-10-10" or "2011-10-10T14:48:00" or "2011-10-10T14:48:00.000+09:00", the results are unpredictable.
Consider instead figuring out what sort of string format you'd be expecting as an input, and then checking if the format is followed with a regular expression. If so, pass to new Date and see if it gives you a meaningful results; otherwise, don't.

As per MDN:
The ECMAScript specification states: If the String does not conform to the standard format the function may fall back to any implementation–specific heuristics or implementation–specific parsing algorithm.
Google Chrome tries to parse your date and picks up the number as a month. Other browsers may reject the passed value or return something totally different.
Hence please consider the following note:
Parsing of date strings with the Date constructor (and Date.parse(), which works the same way) is strongly discouraged due to browser differences and inconsistencies.
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Parameters

From mdn:
A string representing a simplification of the ISO 8601 calendar date extended format (other formats may be used, but results are implementation-dependent).
You're encountering an implementation-specific attempt to parse your string as a date. It is not recommended to depend on this behaviour.

Because your test text includes a number. See, it's interpreting a number like 1 as January, 2 as February,3 as March, and so on.
new Date( "3")
will give you
Thu Mar 01 2001 00:00:00 GMT+0530 (India Standard Time)
If you use text with no number, e.g. new Date("test") it will throw invalid date.

Related

Validate if string is a date [duplicate]

This question already has answers here:
Why does Date.parse give incorrect results?
(11 answers)
How to validate a date?
(11 answers)
Closed 2 years ago.
I've seen many articles about this but not quite found what I am looking for yet.
I'm trying to simply check if a string is a date. That string might contains a number such as 2012 though.
var timestamp = Date.parse('foo 2012');
if (isNaN(timestamp) == false) {
var d = new Date(timestamp);
console.log('DATE', d)
}else{
console.log('TEXT');
}
//OUTPUT: DATE Sun Jan 01 2012 00:00:00 GMT+1100 (Australian Eastern Daylight Time)
Why does javascript convert foo 2012 into a date when it's clearly not?
How can I validate that my string is an actual date ?
A string is never a date.
A string can represent a date. There are many ways to represent the same date through different string formats.
This means "validating that a string is a date" is an impossible task. What you can do instead is:
Validate that the format of the string conforms to some well-known format and that its contents are valid.
Try to parse a given string as an expected format and either throw an error or return a "guard" value to indicate that the parsing was not a success.
JavaScript took a third option, which is like option 2, only it returns a value indicating its "best efforts" at working with the garbage input. That's apparently why it saw a year in your string and decided "well, I guess I can make a date with this?" As #Pointy pointed out, it's actually in the spec that if the JavaScript string doesn't match one of the two supported formats, the implementer can decide what the result should be.
I'd highly recommend that if you're dealing with date strings, you should stick with a consistent format. I'm a big fan of ISO 8601 date/time strings because they are time zone aware, easy to sort, and are widely supported (including being easily parsed by JavaScript). If you're requiring the strings are in a standard format, it's easier to do things like finding A RegExp that can validate the input.

MomentJS - isValid() method is not validating correctly

I'm reading the document for MomentJS for validating a moment date created from a String.
The example they gave is:
1) moment("not a real date").isValid(); // false
but if I add 1 to the end of the String and validate it, I get:
2) moment("not a real date 1").isValid(); // true
Why is it that #2 is a valid moment date object?
Note that that constructor is now deprecated. But to answer the question:
This constructor turns around and passes the "not a real date 1" string into the Date constructor. Take a look at this:
In Chrome:
new Date("not a real date 1") --> Mon Jan 01 2001 00:00:00 GMT-0600 (Central Standard Time)
new Date("not a real date") --> Invalid Date
In IE11:
new Date("not a real date 1") --> [date] NaN[date] NaN
new Date("not a real date") --> [date] NaN[date] NaN
In FireFox 42:
new Date("not a real date 1") --> Invalid Date
new Date("not a real date") --> Invalid Date
So the answer is, it is validating correctly, and its a valid date object because the Date constructor successfully created a Date object. There's a bug in the Date constructor, at least in some browsers.
Edit:
Here's the relevant part of the ECMAScript 6 spec, emphasis mine:
If Type(v) is String, then
Let tv be the result of parsing v as a date, in exactly the same manner as for the parse method (20.3.3.2). If the parse resulted in an abrupt completion, tv is the Completion Record.
And then, section 20.3.3.2:
The function first attempts to parse the format of the String according to the rules (including extended years) called out in Date Time String Format (20.3.1.16). If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats. Unrecognizable Strings or dates containing illegal element values in the format String shall cause Date.parse to return NaN.
So, since the spec explicitly allows the browser to creatively parse the string, I guess it's not a bug. Chrome just doesn't behave the same as the others.

JS Date() - Leading zero on days

A leading zero for the day within a string seems to break the Javascript Date object in Chrome. There are also some inconsistencies between browsers, since Firefox handles the leading zero correctly, but fails when the zero is not included. See this example: https://jsfiddle.net/3m6ovh1f/3/
Date('2015-11-01'); // works in Firefox, not in Chrome
Date('2015-11-1'); // works in Chrome, not in Firefox
Why? Is there a good way to work around/with the leading zero?
Please note, the strings are coming from MySQL via AJAX and all dates will contain the leading zero, and I can fix this by formating the dates server-side. What format would work the best?
EDIT
Just to specify what my problem was, it looks like Chrome is applying a time zone to the YYYY-MM-DD format, which reverts the Nov. 1st date back to the Oct. 31st date (because of my EDT local time).
According to ECMA-262 (5.1):
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.
The date/time string format as described in 15.9.1.15 is YYYY-MM-DDTHH:mm:ss.sssZ. It can also be a shorter representation of this format, like YYYY-MM-DD.
2015-11-1 is not a valid date/time string for Javascript (note it's YYYY-MM-D and not YYYY-MM-DD). Thus, the implementation (browser) is able to do whatever it wants with that string. It can attempt to parse the string in a different format, or it can simply say that the string is an invalid date. Chrome chooses the former (see DateParser::Parse) and attempts to parse it as a "legacy" date. Firefox seems to choose the latter, and refuses to parse it.
Now, your claim that new Date('2015-11-01') doesn't work in Chrome is incorrect. As the string conforms to the date/time string format, Chrome must parse it to be specification compliant. In fact, I just tried it myself -- it works in Chrome.
So, what are your options here?
Use the correct date/time format (i.e. YYYY-MM-DD or some extension of it).
Use the new Date (year, month, date) constructor, i.e. new Date(2015, 10, 1) (months go from 0-11) in this case.
Whichever option is up to you, but there is a date/time string format that all specification compliant browsers should agree on.
As an alternative, why not use unix timestamps instead? In JavaScript, you would would multiply the timestamp value by 1000,
e.g
var _t = { time: 1446220558 };
var _d = new Date( _t.time*1000 );
Test in your browser console:
new Date( 14462205581000 );
// prints Fri Oct 30 2015 11:55:58 GMT-0400 (EDT)
There's a little benefit in it as well (if data comes via JS) - you'd save 2 bytes on every date element '2015-10-30' VS 1446220558 :)

javascript Date.parse assumes 31 days in February and all months?

It seems to me that Date.parse assumes all months have 31 days. Including months with 30 days and including February(which should only ever have 28/29 days).
I checked this question 31 days in February in Date object
But the answer there suggested there was nothing wrong with Date in his issue..Somebody said something to the questioner about zero indexing and he pretty much said "oh ok", and determined that it was his mistake and not a mistake of Date.
Another question Date is considering 31 days of month the guy was doing some subtraction was a number of lines of code and he seemed to not put the error down to Date in the end.
But this example that I have seems to be a bit different and more clear cut. It involves Date.parse and can be demonstrated with one/two lines of code.
Date.parse is aware that there are not 32 days in a month, that's good
Date.parse("2000-01-32");
NaN
But In February it thinks there can be 30 or 31 days
Date.parse("2013-02-30");
1362182400000
Date.parse("2013-02-31");
1362268800000
In fact it looks like it thinks all months have 31 days. That is really strange for a method that is meant to parse a date.
And there's no issue of zero indexing here. As Date.parse("...") doesn't use zero indexing (And even if it did, it wouldn't cause it tot make the error of thinking there are 31 days in February - that is more than one off!
Date.parse("01-00-2000");
NaN
Date.parse("00-01-2000");
NaN
According to the specification for Date.parse() (emphasis mine):
The function first attempts to parse the format of the String according to the rules called out in Date Time String Format. […] Unrecognisable Strings or dates containing illegal element values in the format String shall cause Date.parse to return NaN.
And according to the specification for Date Time String Format (emphasis mine):
ECMAScript defines a string interchange format for date-times based upon a simplification of the ISO 8601 Extended Format. The format is as follows: YYYY-MM-DDTHH:mm:ss.sssZ
Where the fields are as follows: […] DDis the day of the month from 01 to 31.
Therefore, any date with a day of month greater than 31 is illegal and Date.parse() returns NaN.
Please notice that the standard defines a date format, not a date: the static method isn't required to make additional verifications, and everything else is implementation-specific. For instance, Date.parse('2013-02-30') and Date.parse('2013-04-31') both return NaN on Firefox.
The implementation differs between browsers. IE, Edge and Chrome will parse strings that doesn't represent actual dates, but Firefox will return NaN for those strings. The safe thing to do is to consider the result from Date.parse as undefined for date strings where the day falls outside the range of the month.
Browsers that allow parsing of non-existent dates will return a different date. Parsing "2015-04-31" will return the date 2015-05-01. This is the same behaviour as when using new Date(2015, 3, 31), where numbers out of range is allowed and will wrap around into a different month or year. That means that the result is still usable, if you don't mind that some invalid dates turn into other dates in some browsers.
The standard isn't very clear about what values are valid:
Illegal values (out-of-bounds as well as syntax errors) in a format
string means that the format string is not a valid instance of this
format.
The day component is defined as having a range from 1 to 31:
DD is the day of the month from 01 to 31.
However, the format is based on ISO 8601, and that is not a format for parsing strings into dates, that is a format for representing dates as string. Clearly you can't represent a date that doesn't even exist as a string.
Right, so how to check if a date string has a valid value?
with moment is very easy:
export function dateStringIsValid(aDateString){
return (moment(aDateString, "DD/MM/YYYY", true).isValid())
}

How can I parse this date string consistently across browsers?

I'm using Javascript's Date object to parse a string into a milliseconds timestamp. I'm using Date.parse(), and the strings I'm parsing are of the following format: "2012-07-06 12:59:36-0600"
Date.parse performs nicely in Chrome, parsing into the correct timestamp I'd anticipate. However, every other browser returns "NaN" when I run the string through Date.parse().
I know that the Date object implementation is browser-specific, but I'd like to find a javascript solution that's capable of parsing strings of this type for any browser. Any suggestions on what else I could use in Javascript to achieve this?
Convert the input to valid ISO 8601:
Date.parse("2012-07-06 12:59:36-0600".replace(' ', 'T'));
This was tested (and works) in Firefox.
Note:
Note that while time zone specifiers are used during date string
parsing to properly interpret the argument, they do not affect the
value returned, which is always the number of milliseconds between
January 1, 1970 00:00:00 UTC and the point in time represented by the
argument.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/parse
Have you tried DateJS? Maybe you don't want to add another library, but it will solve your crossbrowser problem.
If the format is consistent, you can parse it yourself:
var date = "2012-07-06 12:59:36-0600";
function parseDatetime(input) {
var match = input.match(/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})([-+]\d{4})/);
match.shift(); // discard the "full match" index
match[2]--;
match[4] += parseInt(match[6],10);
return new Date(match[0],match[1],match[2],match[3],match[4],match[5]);
}

Categories

Resources