-2

With Moment.js, For a date string such as 2015-10-05T22:10:00-05:00, I get Invalid dateGMT in the browser DOM. But if I run the script below in the console, line by line, it renders the date with no issues.

var elements = [].slice.call(document.querySelectorAll("a.date_due"));
elements.forEach(function(element) {
    var timeDisplay = moment(element.text).local();
    var zone = timeDisplay.format("ZZ");
    zone = zone == "-0500" ? zone = "CST" : zone = "GMT";
    element.textContent = timeDisplay
                          .format("MMM Do YYYY, ddd, h:mm:ss a ")
                          + zone;
});

UPDATE: Issue was spaces in the element. var requestDate = element.textContent.replace(/\s+/g, '')); was the fix.

dman
  • 10,406
  • 18
  • 102
  • 201
  • 2
    Note that -0500 isn't always CST. In fact, it's early here but: Is -0500 *ever* CST? Isn't it EST (when not on daylight savings time) or CDT (when on daylight savings time)? CST is -0600. – T.J. Crowder Oct 06 '15 at 05:47
  • I think it depends on daylight savings, correct? – dman Oct 06 '15 at 05:48
  • Tried `[].slice.call(document.querySelectorAll())` in IE 8? – RobG Oct 06 '15 at 05:48
  • 2
    No, CST is Central **Standard** Time. During DST, that same part of the world is under CDT, Central **Daylight** Time. – T.J. Crowder Oct 06 '15 at 05:48
  • @T.J.Crowder—the parts work, but IE 8 and lower don't allow host objects as *this* in built–in methods. Try it with `document.getElementsByTagName` or any other list–like DOM object. You can do `[].forEach.call(DOMObject)` because *forEach* is emulated with a native method, not built–in. – RobG Oct 06 '15 at 05:50
  • @RobG: I'm going to be *seriously* surprised if it doesn't work. How could I not know that? :-) *Edit:* Color me surprised! [This](http://jsbin.com/duwaraqeba) fails on IE8. Wow, thanks. Off to add a warning to [this answer](http://stackoverflow.com/questions/9329446/for-each-over-an-array-in-javascript/9329476#9329476). – T.J. Crowder Oct 06 '15 at 05:51
  • @T.J.Crowder hmm... are you sure? I live in texas http://www.timetemperature.com/tzus/gmt_united_states.shtml – dman Oct 06 '15 at 05:54
  • 1
    @dman—the problem with defining timezones with abbreviations like "CDT" is that they aren't officially standardised, e.g. "EST" can be any of 3 different timezones. Consider something like the [*IANA time zone database*](http://www.iana.org/time-zones), or UTC offset. – RobG Oct 06 '15 at 05:56
  • 1
    @dman: Yes, I'm sure. That link confirms it, in fact: Look under "Central" in "Time Zone in United States." To the right it says "UTC Offset Standard Time" is -6 hr, so CST is -0600. "UTC Offset Daylight Saving Time" is -5 hr, so CDT is -0500. – T.J. Crowder Oct 06 '15 at 05:56
  • Thanks for pointing that out, very important. – dman Oct 06 '15 at 05:57

1 Answers1

1

I suspect you meant this line:

var timeDisplay = moment(element.text).local();

to use textContent rather than text:

var timeDisplay = moment(element.textContent).local();

Separately, note that not all browsers support textContent; some use innerText instead (which is slightly different, but probably similar enough for what you're doing).

If you're going to use those properties, early in your script you might want to identify which to use, once, and remember that:

var textPropName = 'textContent' in document.createElement('div') ? 'textContent' : 'innerText';

...and then:

var elements = [].slice.call(document.querySelectorAll("a.date_due"));
elements.forEach(function(element) {
    var timeDisplay = moment(element[textPropName]).local();
    var zone = timeDisplay.format("ZZ");
    zone = zone == "-0500" ? zone = "CST" : zone = "GMT";
    element[textPropName] = timeDisplay
                          .format("MMM Do YYYY, ddd, h:mm:ss a ")
                          + zone;
});

About converting the return value of querySelectorAll and using forEach: As RobG points out, that will fail on IE8 and earlier (which many of us still have to worry about) because A) You can't use slice like that with host-provided objects on IE8, and B) IE8 doesn't have forEach unless you shim it. It's also creating objects unnecessarily.

Rather than create the unnecessary array, just use forEach directly (and shim it if the browser doesn't have it):

Array.prototype.forEach.call(
    document.querySelectorAll("a.date_due"),
    function(element) {
    var timeDisplay = moment(element[textPropName]).local();
    var zone = timeDisplay.format("ZZ");
    zone = zone == "-0500" ? zone = "CST" : zone = "GMT";
    element[textPropName] = timeDisplay
                          .format("MMM Do YYYY, ddd, h:mm:ss a ")
                          + zone;
});

That'll work (if you shim forEach) since either the browser has native support that isn't broken, or you're using a shim.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Actually, this wasn't the root cause. Still having the same issue. – dman Oct 07 '15 at 02:38
  • 1
    @dman: I should have thought of the spaces thing. Since you've figured it out, I suggest posting your own answer to the question showing the fix. The system will let you accept your own answer once the question is 48 hours old. Congrats on figuring it out. – T.J. Crowder Oct 07 '15 at 07:14