Remote-Url: https://zachholman.com/talk/utc-is-enough-for-everyone-right Retrieved-at: 2022-02-21 19:16:08.709567+00:00 Storing TimeThe very first thing you need to start worrying about when you build smart, time-aware software is how you store time. For many, databases will be the tool they’ll reach for. And there’s a lot of things to consider when it comes tohowyou store that data in a database.Step one:use UTC. Okay I’m not going to suddenly say all this advice we’ve been giving for years and years is wrong. UTC is a fine standard to base all your times off of. So use it. Don’t do something silly andchange your servers’ timezones from UTC.Now, I’ve been burying the lede here for quite some time. It’s worthwhile to talk quickly about UTC, and why it’s a good default when we tell developers “Just use UTC”.UTC, of course, stands for:UniversalCoordinaTed…?Cum… lemme figure this out…Time?Time standards bodies got us making scratch pads like some Zodiac Killer letter. Didn’t even know Ted Cruz cared about timezone issues.But yeah, thisUTCinitialism doesn’t make any sense. Let’s dig into this a little more.So you’ve got a bunch of scientist types around 1960 who are like, hey, time is all screwy we should totes make a standard. And some of them spoke English, and some of them spoke French, which, of course, is the cause of so much conflict over so many generations. (In hindsight, maybe we should have split all those troublemakers up from the start.)The English-speaking folk were like yo, this definitely sounds likeCoordinated Universal Time, boom, ship it. And the French speakers were like yeah that makes total sense!Temps Universel CoordonnéDOES work out well in our language, too, ship it! Then they both looked up and realized cool, they’ve created bothCUTandTUCfor acronyms. Shit.When your standard — that is expressly meant tostandardizetime — doesn’t even standardize on a standardacronym, well, damn, that probably doesn’t bode well for your standard.Or, actually, now that I think about it, this might be the most perfect metaphor about time itself ever created. Maybe we should give them some credit for that. Time never makes sense.Anyway, the compromise that arose was that if everyone is special,no one is special, so they created an entirely new set of letters that has no direct relation to any real words for the compromise:UTC.Whew.So. We use UTC because it has anoffsetof 00:00: in other words, it has no timezone offset. Other timezones are offset fromUTC, not the other way around.It’s important to note that UTC isnotGMT. GMT is Greenwich Mean Time, which historically was the center of time in the world. They both have an offset of 00:00. But you shouldn’t use GMT on your server, for example, because UTC is astandard, but GMT is atimezone. People actually live in locations whose time is GMT; UTC isn’t directly used by people (unless they’re really weird).This may sound like such a small difference of wankery, but the more relevant part is thatsomeusers of GMT observe Daylight Saving Time (but not all). UTC has no concept of Daylight Saving Time at all. So if you base everything in GMT, well, who knowssss what will happen.Quick side note: it's DaylightSavingTime, not DaylightSavingsTime. You don't want to sound like a total tool in front of all six of us who care about this stuff.One question you might want to ask right from the start is:do you reallyneedto store time?As programmers, we’re kind of inherently built to want the ABSOLUTE BEST HIGHEST FIDELITY FORMATS OF ALL TIME. Like dammit, Ineedthe timestamp down to the micromillinanosecond for every cheeseburger that gets added to my bespokeWatch-The-BK-Throneapp. If I do not have this exact knowledge to the millisecond of when I consumed this BBQ Bacon WHOPPER® Sandwich From Burger King® I may die.But we sometimes don’t need all this data, and that’s cool, so be sure to ask yourself if you really need this data, or you just want this data. The rule of the game for programming with time is that you should opt to go as simple as possible as soon as possible. A good example of this are birthdays. Birthdays are kind of like floating events; it doesn’t really matter where you are on the planet; if the numerical day matches up with what’s on your driver’s license we’re set. Storing these things as a timestamp column instead of just a date column in your database can end up complicating your code down the line.Properly storing timezone-aware timesOn the other hand, you may actually want to track time. In those cases, there’s a few ways of doing this, particularly if you know that fidelity of hour or minute is going to be important for your use case.Say you have aneventstable in your database, and you toss in a column to keep track of when the event starts:NameTypestarts_attimestampThis is neat and obvious, since you want to store a time as a timestamp in whatever database you’re using. But if it’s important that you don’t end up being an hour off when something actually happened, you’d need to store the originating timezone as well:NameTypestarts_attimestampstarts_at_tzstringBy adding the offset as a string in your database, you gain some additional powers. For one, it gives you a closer idea of whenspecificallythe event happened.One way to do this is to treat this column as an integer; say, store-240in a row to represent a shift of 4 hours (4*60 minutes). That’s cool, and it does get you closer, but again, we’re talking about a use case where it actually does matter to be as accurate as possible (and being off an hour might lead to nonsensical data). Just having a numerical offset doesn’t give you fidelity of location. Was it during Daylight Saving Time? What about comparing that to today’s time; do we account for DST or not? Also, do we need to account for changes in timezones that might have happened since that point in time?Instead of a numeric offset, use a string. Specifically, use thefull qualified namein the Olson database, so something likeAustralia/AdelaideorAmerica/Los_Angeles. These are standardized descriptors of the timezones used in the world, and you can use these in pretty much every programming language ever used in the last few decades.Again, all of this probably isn’t relevant foreveryapp — who cares if someone’s browsing the articleBrad Pitt’s Beautifully Coiffed Hair: Friend or Foe to the Proletariat?and my six comments aretechnicallylisted as an hour earlier than they actually were. Regardless of timing, my comments were perfectly relevant and explored the issue perfectly. But for some apps it might make sense to get this detailed, particularly if you’re comparing a lot of times to each other (like, say, a calendar).The historical side of this stuff gets kinda cool, too. One of my favorite examples is inRFC 3339:1937-01-01T12:00:27.87+00:20This represents the same instant of time as noon, January 1, 1937, Netherlands time. Standard time in the Netherlands was exactly 19 minutes and 32.13 seconds ahead of UTC by law from 1909-05-01 through 1937-06-30. This time zone cannot be represented exactly using the HH:MM format, and this timestamp uses the closest representable UTC offset.So if you really get down into the rabbit hole and find yourself needing historically-accurate times across decades, you might need to backtrack over multiple previous timezone changes in order to get to that point. Also if you find yourself at this critical juncture, you might want to just give up programming entirely, because that sounds horrible.Transiting TimeAight, cool, you’re storing your times correctly; now we can take a look at how we transit those times to our clients.Number one rule:stay consistent.The number one way to address that number one rule:ISO 8601.ISO 8601 is one of my favorite standards and/or RFC out there. And yes, youshoulddefinitely have a favorite. (My all-time fave isRFC 2606, thanks for asking! I’m in awe of that absolute unit. Where would we be without that banger? We’d be in complete fucking chaos, that’s where.)ISO 8601 was a standard that came out in 1988, so it’s probably older than all you lot who are reading this, now get off my damn Friendster lawn. It was re-upped in 2004, 2014, and is anticipating a new draft by the end of this year. It basically defines THE way of writing a timestamp.Here: I’ll even be nice and show you an example:In JavaScript land, this is simple: it just uses thetoISOString()function:The astute among you might see a few reasons right away why this is such a dope format:Easy sorting: It arranges all components from large to small, so pretty much any novice in a programming language could easily sort a list of timestamps from latest to oldest.Timezone information: At the far end it includes the offset:-08:00, for example (well, not in this above example specifically, since in JavaScript you’d also need to parse this out manually withgetTimezoneOffset()). This isn’t as high-fidelity as when we were talking earlier about storing the qualified string version of a timezone, but it does give us information we wouldn’t have otherwise. You don’t get this if you pass aroundUNIX epoch time, for example.No locale problems: You don’t have problems with Month/Day/Year formats getting confused with Day/Month/Year formatted dates. More on this in a few.So yeah, use ISO 8601 over the wire. It’s the most popular way of tackling a shared standard for time, so don’t be the jerk who does it in some fancypants custom manner.RFC 3339Wanted to mentionRFC 3339briefly as well, since sometimes you’ll see its mean mug pop up in APIs and other spots from time to time.RFC 3339 came out in 2002. This is a simplification, but it’s kind of a subset of ISO 8601. It requires timestamps — ISO 8601 allows you to omit them and just use it for a date — and in general it’s slightly more strict. It lets you get away with less.Effectively they’re sort of interchangeable. Most people and API platforms just say they comply with ISO 8601, so that’s probably going to be fine for you, too.Displaying TimeYou’ve got some time, you’ve sent it to the client or to the user… now you have to display it, with hopefully minimal amount of confusion with the United States Secret Service.I don’t know if you’ve noticed this yet, but Americans aren’t perfect. We use this fucked up date format, MM/DD/YYYY. Like under no circumstances does this make any sense. But if you switch that around and try to show someone from the US a date like 24/6/18… well that’s just going to be weird. People like their locale-based date formatting, and you should try to respect that as much as you can.One of the ways you can do this on the web is using theIntlAPI.Intlsupports a number of different hooks and abilities to handle locale- and language-based changes for numbers, plurals, and dates and times.Beyond that, if you’re going to be doing anything fancier with dates and times beyond, say, just printing something to the page, you should really start using a proper time library. Things like adding two dates together while still tracking DST and a multitude of other time rules… well, it’s all really difficult to do yourself. Stand on the shoulders of giants, and steal from someone else. Just how Open Source was intended.Some solid libraries to take a gander at:moment.jsThe classic time library in JavaScript. Date manipulation, formatting, pretty much everything you’d need.date-fnsMore modern approach to a moment.js-like experience for handling dates on the web.github/time-elementsWeb component extension to the