The Problem
I recently discovered an interesting issue with Internet Explorer (IE) 11 after taking IE 11 on a date with some cross-browser testing. Some lazy JavaScript code I’d written to calculate and display calendar dates were rendering as “Invalid Date” in various Html elements. The same JavaScript code worked fine in older versions of IE as well as Firefox and Chrome.
Specifically, any line creating a new JavaScript Date
object with a string fetched from the toLocaleDateString
method would fail, resulting in the display of “Invalid Date”.
Below is a simplified version of the code.
var localeDateString = new Date().toLocaleDateString();
// will show today's date in mm/dd/yyyy format or per your locale settings
console.log(localeDateString);
// the lazy code: locale strings are not meant to be used in the Date constructor
var newDate = new Date(localeDateString);
// If IE11, will show "Invalid Date"
console.log(newDate);
For my locale, I would expect to see the date appear in a mm/dd/yyyy
format, with a maximum length of 10 characters. However, in IE 11, the length of the string generated by toLocaleString()
is reported as 14.
var localeDateString = new Date().toLocaleDateString();
// In all browsers, for my locale, shows "8/22/2016"
console.log(localeDateString);
// in all browsers but IE 11, shows 9. In IE 11, 14
console.log(localeDateString.length);
The Unicode Surprise
Let’s take a look at what IE 11 has added to the output of toLocaleDateString()
. Run the code below in IE 11
for (var i=0; i<localeDateString.length;i++) {
console.log(i.toString() + ' : ' + localeDateString.charCodeAt(i));
}
You should see something like the below, the character index number followed by it’s character code
0 : 8206
1 : 56
2 : 8206
3 : 47
4 : 8206
5 : 50
6 : 50
7 : 8206
8 : 47
9 : 8206
10 : 50
11 : 48
12 : 49
13 : 54
Aha…. character code 8206 has been added and is the Unicode RTL (Right-to-Left) mark and obviously precedes each portion comprising the total date, the mm
, the /
, the dd
, the yyyy
. So that’s what has changed.
IE 11 Date Parser Doesn’t Like Unicode Characters
In the code below, we can see that it is the presence of these Unicode RTL marks which gives the IE 11 Date parser trouble when instantiating new Date objects:
// no unicode characters
var dateString = "8/23/2016";
// seems to work fine in all browsers
console.log(new Date(dateString));
// grab date string with new Unicode characters
var localeDateString = new Date().toLocaleDateString();
// If IE11, will show "Invalid Date"
console.log(localeDateString);
Locale Strings Not Meant for Date Constructors
At the end of the day, the cause of the original problem (“Invalid Date”) was due a combination of lazy JavaScript coding practices with the Date
object combined with the new Unicode characters embedded in IE 11’s locale date strings. If I had not attempted to create new Date
objects using the output from toLocaleDateString
, the problem would not have occurred.
Specifically, strings generated with methods like toLocaleDateString()
are intended as convenience methods to display dates only. Given the diversity of possible date string formats with various locales, it would be impossible for any browser’s Date
parser to consistently parse every locale date string into a new Date
object.
This is why the code below is lazy/not best practices
// bad code: should not attempt to parse locale strings when constructing new dates
console.log(new Date(new Date().toLocaleString()));
Cross Browser Compliant Date Parsing
The original issue eventually led me to re-ask the question: “What is the most reliable cross-browser method for creating new JavaScript Date
objects?”
If there is a definitive answer out there, please let us know. My investigations did not reveal a definitive answer.
However, it led to these findings:
- Consistent date handling across browsers remains a tricky and troublesome area for web developers. Because each browser has it’s own internal implementation for how it parses strings into
Date
objects. - Mozilla’s documentation on the
Date
object suggests using IETF-compliant RFC 2822 or ISO8601 timestamps when creating newDate
objects with thedateString
constructor, but offers an interesting warning against doing so, even with these two standardized datetime string formats:
dateString String value representing a date. The string should be in a format recognized by the Date.parse() method (IETF-compliant RFC 2822 timestamps and also a version of ISO8601). Note: parsing of date strings with the
Date
constructor (andDate.parse
, they are equivalent) is strongly discouraged due to browser differences and inconsistencies. - momentjs is a popular JavaScript library used for handling cross-browser and regional date formatting and calculation issues. Even it’s documentation cautions against constructing new
Date
objects with a single string in the constructor:
Warning: Browser support for parsing strings is inconsistent. Because there is no specification on which formats should be supported, what works in some browsers will not work in other browsers. For consistent results parsing anything other than ISO 8601 strings, you should use String + Format.
The Most Reliable Method Is The Least Convenient
Ultimately, it seems that the most reliable method for creating new JavaScript Date
objects is to use the constructor which takes each date part as a separate argument
new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);
Summary
Writing cross-browser compliant JavaScript is obviously important and highly desirable. Handling JavaScript Dates across browsers consistently continues to be an ongoing challenge for web developers because each browser can have slightly different expectations when working with datetime strings.
If you have been using less-than-ideal methods for creating new Date
objects, such as passing a single datetime string into the Date
constructor, or using Date.parse
, consider converting your code to create new Date
objects with the
new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);
constructor in order to avoid cross-browser differences when parsing dates. Even then, you may need to still handle some browser differences. In many cases, libraries like momentjs may help ease cross-browser pain when working with dates.
Finally, IE 11 has begun to emit Unicode RTL marks into the datetime strings emitted by it’s various toLocaleString()
methods, which causes “Invalid Date” to appear when attempting to create new Date
objects with the Date(dateString)
constructor and the Date.parse(dateString)
method. The newly embedded Unicode characters may cause your existing JavaScript to fail.
Please post any comments, feedback or questions below.