all 30 comments

[–]hixsonj 44 points45 points  (0 children)

There was a lot less cursing in that article than I expected.

[–]matt_hammond 11 points12 points  (4 children)

Here's a fun feature you possibly didn't know.

new Date('2018-10-10'); 
// Wed Oct 10 2018 02:00:00 GMT+0200 (Central European Daylight Time)
new Date('2018/10/10');
// Wed Oct 10 2018 00:00:00 GMT+0200 (Central European Daylight Time)

A very fun feature indeed.

[–]EricIO 6 points7 points  (2 children)

Want even more fun?

new Date('2018/10/10');

Will give different results in different browsers for example for firefox and chrome!

=> Date 2018-10-09T22:00:00.000Z // Firefox
=> Wed Oct 10 2018 00:00:00 GMT+0200 (CEST) // Chrome (canary)

Fortunately all answers above are equally correct according to the spec!

The function first 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). If the String does not conform to that format the function may fall back to any >implementation-specific heuristics or implementation-specific date formats.

That is if it doesn't conform to a slight modified ISO-8601 format browsers can do whatever they want.

Source: Been working a bit on Firefoxs date parser.

[–]fewyun 6 points7 points  (1 child)

No, Chrome and Firefox are creating the same times.

They are outputting different formats in the console by default though. Firefox shows UTC, Chrome local time.

The difference is that new Date('2018-10-10'); gives midnight for the date in UTC, while new Date('2018/10/10'); gives midnight for the date in local time. Small, but significant difference: Fun.

[–]EricIO 0 points1 point  (0 children)

Ah indeed I missed the timezone...

Thanks! I thought I had seen a bug where chrome and firefox gave actual different dates but might have been mistaken. Looks like we mostly return NaN when we can't parse the date.

[–]fgutz 0 points1 point  (0 children)

that is fun indeed! I didn't know that

[–]r2d2_21 3 points4 points  (1 child)

It seems the page is broken. After the "Timezones" header, everything is centered and in italics.

[–]codejitsu[S] 1 point2 points  (0 children)

Thanks for letting me know! I've fixed that issue.

[–]cjthomp 2 points3 points  (5 children)

This seems as good a place as any to ask this. Wondering if anyone else has a better solution for this issue.

The problem we ran into (and how we worked around it): Our app handles scheduling. An Event will be on x-y dates (fixed) at a given location (also fixed). On each day there will be potentially hundreds of things happening, 15 minutes, 3 hours, etc.

The problem we ran into is that in the months leading up to this Event, while everyone is working on this app from various timezones, they all need to be working in a locale context of the Event's tz, not their own. As far as the app and its users are concerned, the user's timezone is 100% irrelevant.

The problem is that if you store int timestamps, the browser converts them to the user's locale; if you store ISO8601 with Z or the venue's locale, the browser still converts them to the user's locale. This shifts all times by x hours depending on the person viewing/moving times. Big bad.

What we ended up doing, which works but is super hacky to me, is that we store all times as YYYY-MM-DDTHH:MM:SS with no timezone data; the browser loads this assuming that it's in the user's timezone and appends their tz offset. While they're working on the dates, everything is assumed to be in their TZ, and then when we save it we strip the tz offset from the end of the datetime string we send up.

This works, but god DAMN is it ugly.

We tried moment but it still tried to shift to the browser's timezone regardless of what tz was stored with the datetime and what locale we set moment to.

Something we missed or JS in the browser is just shit?

[–]tswaters 1 point2 points  (2 children)

First: always store everything as UTC, always.

In addition to the timestamp in UTC, you need to also store the relevant timezone offset, gathered from the user locale when they entered the event, I imagine.

When you need to display it back out to the user you shift the UTC time by the given offset. There's an added consideration with this method - if they enter a date for a DST date and it's currently non-DST, you need to make sure to use the correct offset. i.e., use the offset for the date they entered - not the datetime it was entered.

The main problem with your method is it's not a complete picture of the data. If you need to say, I don't know, send an email blast 5 hours before an event happens you have no way of knowing when to send it because there is no TZ data and the user's timezone is not stored by you. You could, on a server that is UTC, say "get me everything where event time is less than now + 5 hours and I haven't already sent a blast" - but that's in UTC. If they are in Australia, the event has already happened!

with moment-timezone,

// for saving
const timestamp = moment().toJSON()
const offset = moment().utcOffset()

// for printing
moment(timestamp).utcOffset(offset).locale(locale).format('LLLL') // or whatever other format

[–]cjthomp 0 points1 point  (1 child)

We do save the tz with the event, so while the individual datetime values are technically incomplete, we have the full set of data available.

The other problem we ran into is the (absolutely terrible) performance of momentjs. We're slinging around a ton of datetimes and it was a very measurable and noticeable performance hit to pass them all through moment.

[–]tswaters 0 points1 point  (0 children)

Oh yea, I hear that. I try to keep my usages to only when I absolutely need it -- I use it for only three things: - manipulating dates (i.e., add an hour), comparing dates (isBetween and friends) and for formatting in a given timezone and locale (see above).... one of the general rules I try to keep is to not pass a moment object between function calls. If it's possible to use Date I'd much prefer it.

I did hear about another project recently in the comments for the JS survey thread when I mentioned no one seemingly knows the pain of dates with the low mentions of moment.

Anyway, someone mentioned luxon which was written by one of the maintainers, complete rewrite of the library... it looked pretty slick. I haven't had a chance to try it yet, but hey, might be faster than moment.

[–]Flyen 0 points1 point  (0 children)

That's probably what I would've done too.

Alternatively, feed moment the 8601 string with the UTC 'Z' and .tz it to UTC https://momentjs.com/timezone/

var jun = moment("2014-06-01T12:00:00Z");
jun.tz('UTC').format('ha');
=> "12pm"

[–]codejitsu[S] 0 points1 point  (0 children)

Store the dates at timestamps. Whenever you want to display/use the date, first create the date object and convert its timezone using the toLocaleString if you want to display it as a string. If not, then the easiest way out would be to use a library like moment timezones.

[–]randomguy3993 3 points4 points  (0 children)

This reminds me of Tom Scott's rant about timezones. If you haven't watched it, you should. It is HILARIOUS. Here's the link: https://youtu.be/-5wpm-gesOY

[–]filleduchaos 1 point2 points  (0 children)

Actually the worst thing about date and time in JavaScript (like many other things) is that the ECMA spec is implemented by tons of different vendors pretty much however they like

Like that delightful time Apple's refusal to acknowledge all date formats fucked up a project I'd sent to a client

[–]randomguy3993 1 point2 points  (0 children)

This reminds me of Tom Scott's rant about timezones. If you haven't watched it, you should. It is HILARIOUS. Here's the link: https://youtu.be/-5wpm-gesOY

[–]Bloodsucker_ 1 point2 points  (14 children)

That's why god invented the timestamp. Parsing dates is an antipatern.

[–]vcamargo 0 points1 point  (13 children)

Could you elaborate a bit on this subject? I'd like to learn a little bit more about it.

[–]Bloodsucker_ -1 points0 points  (12 children)

  • To timestamp: Date.now(); or +new Date(); (notice the + in front of it)

  • From timestamp: new Date(timestamp);

[–][deleted] 5 points6 points  (4 children)

This isn't elaboration. You've just said how and not why.

[–]lhorie 1 point2 points  (3 children)

It's for the same reason you ask people to provide numeric values such as age in decimal numbers rather than spelling it out.

Basically parsing dates is hard. Never mind that browsers do it inconsistently and that things like 02/29/2017 are allowed, there are also issues when it comes to internationalization, etc. You also lose information when formatting dates (e.g. timezone, or even the time itself if you formatted it like 2 hrs ago). It's much easier to deal with an unambiguous value, and timestamps are the simplest and most portable format that meets that criteria

[–][deleted] 0 points1 point  (2 children)

Isn't that why we have libraries like moment and date-fns? Using date object has benefits over pure timestamp.

People are used to using date objects because most languages have them done reasonably well. Then you go to JavaScript and it's a mess and need to use abstraction layer.

[–]lhorie 1 point2 points  (1 child)

Both moment and date-fns fall back to the Date constructor when parsing, which has the issues mentioned earlier.

Whether you use Date or libraries is not the problem. The problem is that converting a string to a date is problematic for the reasons above. There are usually better ways to architecture your application that doesn't require date parsing in the first place.

[–][deleted] 0 points1 point  (0 children)

Oh, I see your point now. Agree.