1. 9

    What is your favorite pitfall in Date?

    Has to be toISOString(). Claims to return ISO8601, which contains the timezone offset, but instead it just gives you the GMT string, even though it’s perfectly aware of the timezone information:

    // It's 15.44 in Europe/Warsaw
    > dt.getTimezoneOffset()
    > dt.toISOString()
    1. 5

      That is a valid ISO 8601 timestamp. The ‘Z’ (“zulu”) means zero UTC offset, so it’s equivalent to 2020-08-02T15:44:03.936+02:00.

      1. 3

        Oh, it is valid, yes. It’s just less useful than one containing the TZ information that is stored in that Date object. It’s correct, but less useful than it could be (and with little extra effort).

        1. 3

          Ah, I misunderstood you, then. When you wrote “claims to return ISO 8601” I thought you meant that it wasn’t actually an ISO 8601 string.

          So what you mean is that the “encoding” of the of the ISO 8601 string should reflect the local timezone of the system where you call .toISOString()? I.e. 2020-08-02T15:44:03.936+02:00 if you called .toISOString() on a CEST system and 2020-08-02T09:44:03.936-04:00 if you called it on an EDT system?

          1. 2

            I’d expect it to not lose the timezone information, given that it already uses a format that supports that information. It’s not incorrect, it’s just less useful that it could be. Perhaps that’s just the implementation, not the spec – but I’m yet to see it implemented differently. It’s not a huge deal, it’s just frustrating that it could’ve been better at a little cost and yet no one bothered, apparently.

            It’s not about the system it’s called on – that determines the timezone that’s already in the object, as my code snipped showed. I’d expect the data that’s already there to be included in the formatting, instead of being converted to UTC, lost and disregarded. If implemented correctly better, toISOString could’ve been a nice, portable, lossless serialization format for Dates – but as it is, a roundtrip gives you a different date than you started with, because it will now always come back as UTC.

            1. 2

              I would actually assume that getTimezoneOffset is a class method that just looks at your system’s configured time zone and does not read anything from the Date object. I’m pretty sure the object does not store information about the timezone of the system in which it was generated, because it’s never needed. You can always convert to the timezone you want at read time.

              This is also what PostgreSQL does. If you create a column for “timestamps with timezone” it will discard the timezone information at write time and just use UTC (because why not?). The only thing that is different when you choose a timestamp column with timezone is that at read time it will convert values from columns to the configured timezone. All it stores is the number of seconds since the epoch.

              If you look at Firefox’s JS source, it looks like they also just store the seconds since the Unix epoch in a Date object, no timezone information: https://github.com/mozilla/gecko-dev/blob/d9f92154813fbd4a528453c33886dc3a74f27abb/js/src/vm/DateObject.h

          2. 3

            I don’t believe Date contains a time offset. As far as I’m aware, like many languages, the problem is not that the APIs ignore the time offset - they would have to silently reach into the client locale to get it, which would be misleading and make it easy to create bugs. the problem is that they named it “Date” when it’s really just a point in absolute time. Combine a Date with the client locale’s time offset and you’ve got yourself a date, but a Date is not a date.

        2. 5

          This is a namespacing error that’s common when methods are on objects like this. getTimezoneOffset is a property here of the client locale, not of the date time object.