What is needed for a valid Javascript Date object? - javascript

I've been banging my head over this one all day. No matter how I initialize a Javascript Date I cannot seem to get a valid Date object... I'm assuming the Date is invalid and not working properly by inspecting it with Chrome's debugger, which has the value '__proto__: Invalid Date'.
I've tried all of the following:
var d = new Date();
var d = new Date('2012-10-08');
var d = new Date('2012-10-08 00:00:00');
var d = new Date(Date('2012-10-08'));
var d = new Date(Date.parse('2012-10-08'));
var d = new Date(2012,10,08);
var d = new Date("October 13, 1975 11:13:00");
Along with countless other attempts.
This is presenting a problem in iOS where I'm trying to get values from these Date objects but every function just returns NaN. I'd prefer to avoid having to use external libraries or have to convert YYYY-MM-DD format into any other format since I'm trying to get this to work with an HTML5 input type="date" with minimal code for a mobile site.
Essentially this boils down to: What are the parameters that make a Date object valid?!

Do not trust the Date object to parse strings, you must do it manually. Given the format 2012-10-08,
function stringToDate(s) {
s = s.match(/\d+/g);
if (s) {
return new Date(s[0], --s[1], s[2]);
}
}
You may want to do some validation of the input string and the resulting date object, the above just shows the conversion.
Edit
BTW, the only string format that seems to be parsed consistently in all browsers is the US-specific month/date/year format. There is no specification to support its use, nor is there any reason to believe browsers will continue to support it other than pragmatism and "legacy" reasons.
For the vast majority of regions, '2/3/2012' is interpreted as 2 March, so getting 3 February might be unexpected.
Once older versions of IE are no longer in use (probably a few years yet), it should be safe to use the ISO8601 extended format per ECMA-262. However, even browsers that support it are inconsitent. e.g given:
new Date('2011-02-29');
Firefox 15 returns 'Invalid Date', IE 9 and Chrome 22 return a date object for 1 March, 2011.

There are three ways of calling the method:
The number of milliseconds from the epoch:
new Date(milliseconds)
Any IETF-compliant RFC 2822 timestamp:
new Date("November 2, 1988 10:00:00");
Individual args:
new Date(year, month, day [, hour, minute, second, millisecond])
new Date(1988,11,02,10,0,0);

If your main concern is about parsing, have a look at Moment.js which is clearly superior to parsing things yourself. (IMHO)

Turns out jQuery doesn't bind the .change() event to input type="date" properly in iOS. Changed the event to .blur() and everything seems to work now. However, it still seems it is impossible to create a valid date object in Chrome... an issue for another day.
Thanks for the help everyone!

Related

When converting date, I get previous day

I want to convert a string into a date "as it is".
const date = "8/16/2019"
console.log(new Date(date))
However, I get:
As you can see I get the prevous day. I was thinking that it might be a timezone issue, even though there is no timezone that I am converting it from.
Any suggestions how to convert is as it is?
I appreciate you replies!
If your format is consistent, you could split on / and use Date.UTC. Creating your new Date from that would ensure it's UTC.
const date = "8/16/2019"
const [month,day,year] = date.split("/");
const utcDate = Date.UTC(year,month-1,day);
console.log(new Date(utcDate));
const date = "8/16/2019"
console.log(new Date(date).toLocaleString("en-US", {timeZone: "Asia/kolkata"}))
Note:- You need to add timezone
You can use toLocaleDateString
console.log(new Date("8/16/2019").toLocaleDateString('en-us', {timeZone: "Asia/Kolkata"}))
new Date("8/16/2019") will create a date object using your current timezone. Add a "Z" at the end if you want your date to be in UTC.
console.log(new Date("8/16/2019Z"))
EDIT
It appears that Firefox is not implementing the parsing of standard date format. Unfortunately until recently how exactly was a date parsed was completeley based on heuristics and intrinsically non portable.
Looking at Firefox bug tracker seems the issue has been discussed but the problem is still present (some toolkit just works around by replacing "Z" with "+00:00" before calling the parser).
The only way to be sure on every browser is to parse the string yourself and build the date from the fields. I didn't notice because I'm using chrome instead (in both chrome and Node works as expected).
EDIT 2
After more investigation seems the standard requires that:
If you use yyyy-mm-ddThh:mm:ssz then you get what ISO format for datetime defines it to be. Also the syntax described in the standard is not very precise and for example is not clear to me if the time zone can be present when no time is present (Chrome says yes, Firefox says no).
If you use another format then anything goes (so for example there is no string that is guaranteed to issue an invalid date response).
In other words new Date("8/16/2019") is not portable Javascript (with the meaning that you don't know what date / time / timezone you will get, if any). Either you parse yourself the date or you just live with what that version of that Javascript engine in that moment decides to give you.

Why is 2/8888/2016 a valid date in IE and Firefox?

If you take the following:
var s = "2/8888/2016";
var d = new Date(s);
alert(d);
In Chrome, you'll get:
Invalid Date
But in IE and Firefox, you'll get:
Fri Jun 01 2040 00:00:00 GMT-0500 (Central Daylight Time)
It appears to be just adding 8888 days to Feb 01. Instead, I would expect the date to be considered invalid. Is there a way I can make FireFox and IE think this date string is invalid?
Short answer:
It's a misbehaviuor of the browsers you're mentioning.
You have to check date is in correct format on your own. But it's quite trivial, I suggest this approach:
Split the date in year y, month m, day d and create the Date object:
var date = new Date( y, m - 1, d ); // note that month is 0 based
Then compare the original values with the logical values obtained using the Date methods:
var isValid = date.getDate() == d &&
date.getMonth() == m-1 &&
date.getFullYear() == y;
Before doing all of this you may want to check if the date string is valid for any browser:
Detecting an "invalid date" Date instance in JavaScript
Long answer:
Firefox (and IE) accepting "2/8888/2016" as a correct string sate format seem to be a bug / misbehaviour.
In fact according to ECMAScript 2015 Language Specification when Date() is invoked with a single string argument should behave just as Date.parse()
http://www.ecma-international.org/ecma-262/6.0/#sec-date-value
The latter
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)
..that is specified here
http://www.ecma-international.org/ecma-262/6.0/#sec-date-time-string-format
where you can read
The format is as follows: YYYY-MM-DDTHH:mm:ss.sssZ
[...]
MM is the month of the year from 01 (January) to 12 (December).
DD is the day of the month from 01 to 31.
It seems that Firefox is interpreting the string value as when Date() is invoked with multiple arguments.
From
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
Note: Where Date is called as a constructor with more than one argument, if values are greater than their logical range (e.g. 13 is provided as the month value or 70 for the minute value), the adjacent value will be adjusted. E.g. new Date(2013, 13, 1) is equivalent to new Date(2014, 1, 1), both create a date for 2014-02-01 (note that the month is 0-based). Similarly for other values: new Date(2013, 2, 1, 0, 70) is equivalent to new Date(2013, 2, 1, 1, 10) which both create a date for 2013-03-01T01:10:00.
This may explain how "2/8888/2016" turns into 2040-05-31T22:00:00.000Z
There's no way to make IE and FF think it's invalid, except:
you could change their javascript implementations
you use a library instead to deal with that.
We can also expect that Javascript, as a language, evolves and we can cross our fingers that browsers decide to follow a more strict specification. The problem of course is that every "fix" must be also backward compatible with previous versions of the language (does not happen always, Perl for example).
So the best thing by now is to use some library just like momentjs as suggested by Derek in the post comments.
You have stumbled across yet another reason why you should manually parse date strings.
When Date is provided a single string argument, it is treated as a date string and parsed according to the rules in Date.parse. The rules there first attempt to parse it as an ISO 8601 format string. If that doesn't work, it may fall back to any parsing algorithm it wants.
In the case of "2/8888/2016", browsers will first attempt to parse it as an ISO format and fail. It seems from experimentation that IE and Firefox determine that the string is in month/day/year format and effectively call the Date constructor with:
new Date(2016,1,8888);
However, other browsers may attempt to validate the values and decide that 8888 is not a valid date or month, so return an invalid date. Both responses are compliant with ECMA-262.
The best advice is to always manually parse date strings (a library can help, but generally isn't necessary as a bespoke parse function with validation is 3 lines of code) then you can be certain of consistent results in any browser or host environment.

How do I format a Javascript date like 1950-12-30T18:25:43.511Z

I have an API where I the date need to be formatted like this
1950-12-30T18:25:43.511Z
This format looks somewhat unfamiliar to me, and I'm wondering how I can take a format like this
1950-12-30
and turn it into something like the former. FYI I'm using javascript (express)
You are trying to put the date into ISO format and the native Date object will do that for you, fairly simply, with the .toISOString() method:
var newDate = new Date("0977-03-28");
console.log(newDate.toISOString());
The result of that is: 0977-03-28T00:00:00.000Z (look familiar? :D )
One issue that you will have (if it is an issue), is that, because you only have the date value, and not a time value, the last part of the string will always be T00:00:00.000Z (which is the "time" section of the Date). You'll see that if you use today's date, using var newDate = new Date(); (which captures this instant), the time will be filled in: 2015-02-19T16:50:18.078Z (at the time of testing)
For more information, see here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
(Note: in IE, this only works in v9 or later, though, that link also has a polyfill for older IE versions)

Javascript milliseconds notaion was not working in firefox

Can anyone help me with this ?
var current_date=new Date('2012/12/21 22:59:59.997');
var result=current_date.getTime();
Im not getting result in Firefox but it does show in chrome, in FF it shows invalid date.
You should be able to do the following (using date.setMilliseconds):
var dateString = '2012/12/21 22:59:59.997';
var dateStringSplit = dateString.split('.');
var myDate = new Date(dateStringSplit[0]);
myDate.setMilliseconds(dateStringSplit[1]);
console.log(myDate);
Firefox and some other browsers (namely, Safari or Opera) don't like milliseconds.
// Split off the part after the dot
var current_date = new Date('2012/12/21 22:59:59.997'.split('.')[0]);
// Works everywhere!
var result = current_date.getTime();
If you really want to work with milliseconds, you have to split the date in multiple parts and use new Date() with those. From MDN documentation, here are the options:
new Date(year, month, day [, hour, minute, second, millisecond])
Or, as h2ooooooo says, you can use the second part of the split date and use setMilliseconds.
Overall, you have plenty of solutions. Choose the one that annoys you the least.
The format you are using is not a standard format for Date.parse
You may want to split the string and set the parts individually. Also, please manage the time zone correctly as it is not apparent which timezone the date string is in.

JavaScript validate existence of date

I have a date in the format YYMMDD. Is there anyway I can validate it in JavaScript?
By validation I don't mean easier things like length, characters etc but rather if the date exists in real life.
I'm hoping there is a faster / better way than breaking it in 3 chunks of 2 characters and checking each individually.
Thank you.
try to convert it to a date and if it fails, you get the dreaded NaN then you know it is not a valid date string? Not Pretty but it should work
var myDate = new Date(dateString);
// should write out NaN
document.write("Date : " + myDate);
You date string would have to be in a valid format for javascript I don't think what you have in your question YYMMDD is supported
The format YYMMDD is not supported by Javascript Date.parse so you have to do some processing of it like breaking it in parts.
I would suggest building a function that splits it in 3 2 char strings and then builds an american style date
MM/DD/YY and try to parse that with Date.parse.
If it returns anything but NaN then its a valid date.
The Date parser in JavaScript is pretty useless. The actual formats it accepts vary greatly across browsers; the only formats guaranteed to work by the ECMAScript standard are whatever formats the implementation's toString and toUTCString methods produce. In ECMAScript Fifth Edition you will also get ISO-8166 format, which is nearer to your format but still not quite.
So, the best solution is usually to parse it yourself.
var y= parseInt(s.slice(0, 2), 10)+2000;
var m= parseInt(s.slice(2, 4), 10)-1;
var d= parseInt(s.slice(4, 6), 10);
var date= new Date(Date.UTC(y, m, d));
Now you've got a Date object representing the input date in UTC. But that's not enough, because the Date constructor allows bogus months like 13 or days like 40, wrapping around. So to check the given day was a real day, convert back to year/month/day and compare:
var valid= date.getUTCFullYear()===y && d.getUTCMonth()===m && d.getUTCDate()===d;

Categories

Resources