0

I'm trying to create a UTC date from an array of values. The documentation states that if any of the parameters are omitted it should default to 0 or 1.

Syntax:

Date.UTC(year, month[, day[, hour[, minute[, second[, millisecond]]]]])

Example:

var tp = [2019]
var d  = new Date(Date.UTC.apply(null, tp))
console.log(d.toString())

Result: "Invalid Date"


Example #2:

var tp = [2019, 01]

Result: "Thu Jan 31 2019 18:00:00 GMT-0600 (CST)"
Expected: "Thu Jan 1 2019 00:00:00 GMT-0600 (CST)"


Could somebody explain what's happening here?


Update:

I should clarify that I was using the API as MDN states. The issue was that Safari does not have an up to date implementation. This was verified with the help of another SO user, who fortunately updated the documentation.

The second example came from a misunderstanding that .toISOString() was zero-indexed, whereas it produces values with a timezone offset of 0, not that the months are zero-indexed.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Levi Roberts
  • 1,277
  • 3
  • 22
  • 44
  • Your first code block [works for me](http://jsfiddle.net/q369asxt/) (Chrome, Firefox, and Edge). Your second example is just a timezone problem (and using the wrong value for January, which is 0, not 1) (and using 01 for 1, don't put leading zeros on literal numbers). – T.J. Crowder Jan 13 '19 at 15:07
  • 1
    You’re making a UTC date with `Date.UTC`, so you got 00:00 UTC instead of 00:00 CST. Also, that signature shows `year, month` as required, with all the optional values in square brackets. – Ry- Jan 13 '19 at 15:07
  • 1
    The "Syntax" you've shown for `Date.UTC` [is incorrect](https://tc39.github.io/ecma262/#sec-date.utc). `month` is not required. Looks like it was [on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC). I've fixed it. – T.J. Crowder Jan 13 '19 at 15:10
  • 1
    @T.J.Crowder: It’s not flat out incorrect, just outdated. The month was required in ES5 ES2016, so Example #1’s *Invalid Date* could have come from an old environment. – Ry- Jan 13 '19 at 15:14
  • Which is one of the reasons I posted the question. I am receiving an Invalid Date in both Safari and `node.js`. Does this mean it is a bug? – Levi Roberts Jan 13 '19 at 15:14
  • 1
    @Ry- - Why, [sure enough](http://ecma-international.org/ecma-262/5.1/#sec-15.9.4.3). :-) – T.J. Crowder Jan 13 '19 at 15:15
  • 1
    @LeviRoberts - I can replicate your results with iOS Safari on my *fairly* recently-updated iPad. It must be a fairly old version of Node, though: Node v8 (v8.11.2) handles it fine (Node v7.10.1 doesn't like it). So it was updated to match the spec change somewhere between the two. If you need to support older environments, just add `0` to the array (`[2019, 0]`). – T.J. Crowder Jan 13 '19 at 15:26
  • 2
    @Ry- - Thanks for fixing that. Normally I check these things more carefully than that! (I'm assuming you're rno on MDN, from the similar of names and locations ;-) ). – T.J. Crowder Jan 13 '19 at 15:42
  • 1
    When you reference "*the documentation*" you should include a link as there are many sites that claim to document ECMAScript or javascript. MDN is a public wiki, anyone can register and update its articles, it's not a normative reference (but it is very helpful). ;-) – RobG Jan 14 '19 at 03:24

1 Answers1

3

Example #1

The line that you quoted indicates that both the year and month are required in ES5- environments. You can't just pass the year if you need to support older execution environments.

However, as T.J. Crowder points out in the comments, this code seems to work. What browser are you trying it in?

Example #2

Months in JavaScript dates are 0-indexed. This means that the month 1 (or 01) is February.

So Date.UTC(2019, 01) produces the timestamp for midnight, February 1, 2019 UTC, which would correspond to 6 PM, January 31, 2019 CST.

One more thing: You should avoid preceding JavaScript number literals with 0 as this is the syntax for representing octal. This means that 020 === 16.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • 1
    The quoted line [is incorrect](https://tc39.github.io/ecma262/#sec-date.utc), `month` is not required. It's not just that it works, it's that it's *specified* to work. – T.J. Crowder Jan 13 '19 at 15:09
  • .toISOstring() is supposed to be 0 indexed then. But the result I get for January is 01. Can you explain that? – Levi Roberts Jan 13 '19 at 15:12
  • @LeviRoberts No, in ISO strings `01` is January. ISO strings and JavaScript dates are two different things. – JLRishe Jan 13 '19 at 15:13
  • @LeviRoberts - No, the contents of the ISO string and the `month` parameter of the `UTC` function are not the same thing. The ISO string is meant to be human-readable, and so uses 1 = January. The `month` parameter in all JavaScript date APIs, however, is for programmers, and counts like a programmer -- 0 = January. – T.J. Crowder Jan 13 '19 at 15:13
  • Although I dislike doing this to SO. Is there a way to parse the ISO string? Could I just reduce by 1 to receive the expected output? – Levi Roberts Jan 13 '19 at 15:16
  • Furthermore, the MDN docs state that `.toIsoString()` is zero indexed. `The timezone is always zero UTC offset, as denoted by the suffix "Z".` – Levi Roberts Jan 13 '19 at 15:18
  • 3
    @LeviRoberts The line you're quoting says that it produces values with a timezone offset of 0, not that the months are zero-indexed. – JLRishe Jan 13 '19 at 15:20
  • @LeviRoberts - And yes, `toISOString` produces a string in [the (only) format](https://tc39.github.io/ecma262/#sec-date-time-string-format) supported by `new Date` and `Date.parse`, so you can use that to parse it if you need to. – T.J. Crowder Jan 13 '19 at 15:21
  • What I'm trying to accomplish is to parse partials. `var d = new Date('20190109')` says `Invalid Date` also. – Levi Roberts Jan 13 '19 at 15:22
  • 1
    @LeviRoberts You can use partials as long as you use a [valid date time string](https://stackoverflow.com/questions/51715259/what-are-valid-date-time-strings-in-javascript/) (see section "Short Date (and Time) Forms" and make sure to also read section "Browser Support"). – str Jan 13 '19 at 15:25
  • 1
    @T.J.Crowder—as of ECMAScript 2018 there are 3 formats that that are required to be supported by the built–in parser: those produced by *toString*, *toISOString* and *toUTCString* which are now specified in ECMA-262. – RobG Jan 14 '19 at 03:12
  • 1
    @str—your statement "*You can use partials…*" must be further qualified to include parsing is **implementation dependent** and that `Invalid date` is a conforming result. Your linked answer also needs updating as there are 3 formats to be supported as of ECMAScript 2018. See [*Why does Date.parse give incorrect results?*](https://stackoverflow.com/questions/2587345/why-does-date-parse-give-incorrect-results). – RobG Jan 14 '19 at 03:17
  • 1
    @LeviRoberts—I think [*Why does Date.parse give incorrect results?*](https://stackoverflow.com/questions/2587345/why-does-date-parse-give-incorrect-results) will help you understand some issues. `new Date('20190109')` is not a "partial", it will be parsed by the built-in parser as a string timestamp and most likely result in an invalid date because the format is not recognised. The built-in parser should be avoided, use a library or custom parse function, they're pretty easy to write. – RobG Jan 14 '19 at 03:29
  • 1
    @RobG - Ah yes, I I always forget `toUTCString`. :-) And am interested to see the change to `toString` in ES2018. No longer the old pseudo-spec not saying what the format was, but saying it had to parse whatever it created... – T.J. Crowder Jan 14 '19 at 07:47
  • @RobG thank you for the reference. It does clarify things. – Levi Roberts Jan 14 '19 at 21:09