Last active
November 28, 2018 00:16
-
-
Save thomasboyt/bee725d9c7ee74f14cd56c8d57e2f335 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import moment from 'moment'; | |
/** | |
* XXX: Okay, so, no date library, other than moment, appears to currently | |
* support _formatting a date with a specified time offset_. That is, given the | |
* date string `2018-11-21T15:00:00+0100` (UTC+1:00), I want to format it as | |
* `3:00 PM`, regardless of the system's current local time. | |
* | |
* This seems like it should be easy, right? We don't need time zone data, | |
* because we're not specifying a time zone, just a UTC offset. All we need to | |
* do is basically parse out the string and format it back with the same offset | |
* it came in as. | |
* | |
* However, browsers are bad. JS Date objects more or less always get converted | |
* into UTC during parsing, and get converted into system-local time during | |
* formatting. Libraries like dayjs and date-fns further extend this behavior. | |
* | |
* You might think this would be a good use case for the fancy new Intl API, | |
* which supports time zones on newer browser. However, this API _requires a | |
* time zone name_, like 'Europe/Paris', to be passed when formatting, and | |
* doesn't support just passing a UTC offset. | |
* | |
* This left us with a few options: | |
* | |
* a) Add/subtract time from a system-local time to format in the offset time. | |
* This would require us to manually parse the UTC offset of the timestamp (the | |
* +XX:YY bit), and use time math to add both the system-local UTC offset, and | |
* the UTC offset of the timestamp, to a local time, then format it. This means | |
* that, on a system in the America/New_York zone, "3 PM Paris time" would | |
* become "9 AM New York time", then we'd add 5 hours for the UTC offset of New | |
* York, then 1 hour for the UTC offset of Paris, and the date would be "3 PM | |
* New York time", which would just get formatted as "3 PM". I don't like the | |
* idea of writing and maintaining this. | |
* | |
* b) Write custom logic just to parse and format the time part of an | |
* ISO8601-formatted time. I did this and hated how it looked, but it worked. | |
* This is the "low-cost" option, with only ~20 lines of new code, but also a | |
* bunch of tests and maintanence and a bunch of changes if you decide you want | |
* to format times in a more complicated way than just "3:00 PM". | |
* | |
* c) Pull in moment, which has moment.parseZone(). parseZone() is kind of a | |
* misnomer, because it doesn't actually handle _time zones_, just UTC offsets. | |
* Using `moment.parseZone(timeStamp).format()` will format your time with the | |
* same offset as specified in the timestamp. | |
* | |
* I'm going with (c), because it we're already using it elsewhere in our | |
* codebase (albiet not yet in this particular application, and while it's 12kb | |
* of additional JS, it's worth it to not have extra overhead). | |
*/ | |
export default function formatTimeWithZone(timeString, fmtString = 'h:mm A') { | |
return moment.parseZone(timeString).format(fmtString); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment