Hacker Newsnew | past | comments | ask | show | jobs | submit | tluse's commentslogin

Pro tip: never ever use anything but ISO dates in UTC tz unless you're displaying it for a user in a UI.


What if you're storing a calendar date, such as a birthday? A timestamp is inappropriate, and it's meaningless to discuss timezones in this context.

(Example - you want to know if a person is old enough to buy cigarettes, and you need to store a birthday that you can compare against the current day to see if they're legally 18 - if you store an epoch at UTC, do you store the time of day they were born? That's not the way the law works. Do you store midnight UTC? If they're currently in NY, can they but cigarettes at 7pm the day before their birthday because they're currently 18 in London?)

Sometimes you need a logical calendar date, not a point in time in the history of the universe.


That’s a great question. ISO 8601 doesn’t allow timezone offsets on date-only strings.

If you were born in the US, can you buy cigarettes at 12:00 am on your 18th birthday in London?

I’ve never heard of age verification laws caring what timezone you were born in. In fact, you couldn’t even pinpoint this from many people’s ID cards. Plenty of US states span multiple time zones, and I wouldn’t be that surprised if there were a maternity ward out there sitting on a TZ line.


The answer is that no age related verification-problem in real world is so sensitive that a day plus or minus would make any difference. So they skip the entire clusterfuck of a problem of timezones by just ignoring them.

I grew up in a country where you could legally buy beer with 16 and and hard alcohol with 18. So if the answer to "when should someone be allowed to choose to drink alcohol" has a variance of multiple years between countries who cares about a day or two.


Simple answer is no, since your ID doesn’t have a time zone of birth on it, they have to read it as local time.


All solutions have problems, but I think UTC midnight is simpler than dealing with mixed date formats in the backend.


It’s 2025 and major backend stacks have domain-specific time types like LocalDate etc. Using them is the only correct and actually the simplest solution.


If you want to store a date you don't need to store a time, time zone, etc. and your question goes away.

Certainly if you want to store birth dates and do age verification there is no point bothering with these issues, just store calendar date. Trivial to get date for age limit purposes.


RFC3339.

ISO 8601 allows for 2 or 6 digit years. Truncating to 2 is just incorrect, and 6 digits is absurd. And you can read the RFC without paying ISO - and you can discuss the RFC with people who have also read it instead of relying on people using the Wikipedia page to interpret and explain ISO 8601.

I have a scheduling service at work and I keep getting requests for implementing ISO 8601 timestamps but I ignore them. RFC3339 is the way forward.


There's this handy venn diagram that I've seen floating around for a long time.

Just found a random link to it with an image search:

https://gyazo.com/d8517f72e24c38f055e17182842b991c/max_size/...

ISO 8601 does have some strange formats...


That's a screenshot of this website:

https://ijmacd.github.io/rfc3339-iso8601/


Thanks! That's where I remember it from.


> ISO 8601 does have some strange formats...

Not that I’ve ever really had cause to use it in anger, but I like the idea of ISO week dates.

Effectively, the ISO weak year (often differs from the calendar year in the last week of December / first week of January), ISO week number and day of week form a leap week calendar - instead of having 365 days in a common year and 366 in a leap year, it has 364 days in a common year and 371 in a leap week year, with leap weeks (obviously) being less frequent than leap days.

The Sym454 calendar [0] takes this idea further to create a perpetual calendar, with 12 months of 4 or 5 weeks; in leap years the 12th month is 5 weeks instead of 4 weeks long. However, the leap week rule proposed by Sym454 is different from that proposed by ISO 8601; the author of Sym454 argues his proposed rule has theoretical advantages (simple calculation and more uniform distribution of leap weeks). That said, there is a variant of Sym454 which uses the ISO 8601 leap week rule.

[0] https://kalendis.free.nf/symmetry.htm?i=1


I believe two-digit years haven't been allowed for a while:

> ISO 8601:2000 allowed truncation (by agreement), where leading components of a date or time are omitted. Notably, this allowed two-digit years to be used as well as the ambiguous formats YY-MM-DD and YYMMDD. This provision was removed in ISO 8601:2004.

(That's from https://en.wikipedia.org/wiki/ISO_8601 - I don't have the standards handy, ironically.)

Honestly I'm happy with either the RFC or ISO, but it seems like most normies haven't heard of RFCs so ISO is my default.


I believe you. But I haven't paid ISO for the pleasure of reading the actual spec so that passed me by.


Plus RFC3339 allows you to use a space instead of the ugly T delimiter between the date and time.


> 6 digit years

Totally insufficient for capturing important future events like the dead of the sun.


And unless you need the original date, time and time zone.

Conversion to UTC is not injective e.g. when clocks change or politics happen


I disagree, store UTC time and the name of timezone it was originally recorded in so it can be translated back to that as well.

UTC only loses information.


> and the name of timezone

The problem is that can be difficult to portably determine. One wishes POSIX had an API “give me IANA time zone name for current process” which would do the needful to work it out (read TZ environment variable, readlink /etc/localtime, whatever else might be necessary)… but no, you are left to do those steps yourself. And it works reasonably well if the TZ environment variable is set, but it most commonly isn’t; readlink of /etc/localtime works on macOS and some Linux distros… but others make /etc/localtime a regular file not a symlink, which makes it all a lot harder

And that’s POSIX. Then there’s Windows which is possibly the last platform to still use its own timezone database instead of IANA’s. Now, Unicode CLDR maintains a Windows-to-IANA mapping table… but you have to ship both that table, and maybe the IANA timezone DB too, with your app, and keep them updated

I really wish Microsoft would ship the IANA database with Windows, and the IANA-Windows mapping table too, and provide APIs to query them, and keep them updated with Windows update. The core Windows OS and existing Windows apps can keep on using the legacy Windows TZ database for backward compatibility, whereas portable apps could use IANA instead if they wish


> I really wish Microsoft would ship the IANA database with Windows, and the IANA-Windows mapping table too, and provide APIs to query them, and keep them updated with Windows update.

I think they have done exactly what you describe for several years at least:

https://learn.microsoft.com/en-us/dotnet/api/system.timezone...


That’s a .Net API, so not easily usable from native code. If they offered a C API instead, almost anything could feasibly use it.

Plus, from reading that doc, it sounds like it only works on Windows if you enable “App-Local ICU” mode, in which case the ICU DLL is added to your .Net app’s distributable package - which implies the info isn’t actually bundled with Windows itself

Consider Python’s zoneinfo standard library module-it provides access to IANA TZ database. On all platforms except Windows it uses the copy of the DB bundled with the OS and updated by the OS update mechanisms. On Windows, you have to install a PyPI module containing it. If Microsoft bundled it with the OS, with a C (not .Net) API, you wouldn’t have to do that-but Microsoft doesn’t, so you do


You conceivably need more than that. You need to know the location (NOT just the time zone) where it will occur, the time zone that location was in when the meeting was created, and the time zone that location is in when the meeting actually happens. The users' systems or whatever does final display need to know their own time zone(s), and how to convert.

Say, for a somewhat annoying-case example, you want to store a meeting date/time that's in the future, in January, in the city of New York, New York, USA, with remote participants elsewhere in New York state. Sometime in between when the calendar invite is created and the meeting the city of New York decides to change to be on permanent Daylight Savings Time, but the rest of New York state doesn't change. If you stored only the UTC time and "America/New York" you now have an ambiguous meeting date/time, since the "America/New York" time zone split and the city of NY is an hour off from the rest of NY for part of the year, and your remote participants could get the wrong time.

There's probably an even worse case involving the death of a Japanese emperor, since the "period" portion of a Japanese date is the imperial name of the emperor who ruled at that time, and that gets retroactively applied to dates between when the new emperor's coronation and when they took their new imperial name.


Yes, but whose timezone? The machine? The user? What about a machine to machine transaction?


Why not store it as a time date in the original timezone then?


You still need the timezone name to map back to UTC, in case you want to make some types of computations, usually along the lines of "how long ago was this" and "remaining time until this thing happens".

You may argue that we can use local time to make the computations and be done with it, but during DST transitions, local time jumps so the number of actual seconds won't be consistent.


There's a good post about why this isn't as foolproof an approach as it might first seem here https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a...


The post doesn’t account for the case where a suburb of Amsterdam breaks off from the rest of Netherlands and changes timezones… Then how do you know if the event was in the neighborhood or not?

My point is that this is an extremely niche case and works around one particular type of timezone insanity. You either have a team dedicated to dealing with timezone insanity, or you store stuff in UTC.


No, but that is an even less likely situation, compared to the problems that the approach advocated for by Jon Skeet actually solves.


Pro tip #2: never ever rely on automatic parsing of dates. It's a lie and will corrupt your data.

Either use dedicated "from_iso8601" functions, or manually specify the format of the input string ("%Y%m%dT%H%M%SZ")


The list of things that devs should "never ever" do grows by the day... turns out most things, even the simplest of things, even sometimes the most apparently trivial things (like naming of people, too) are in reality almost always much more complex and difficult to get right on the first go than expected.

But then discussion ensues about how programmers these days add libraries as dependencies for almost everything! :-)

I guess at some point a middle ground must be found.


  > never ever use anything but ISO dates in UTC tz unless you're displaying it for a user in a UI.
Not good for storing future meeting times. DST switchover dates can change, and your tz-normalized date won't change with it.


Or if you really want to be future proof, store the geolocation so you can try to figure out the jurisdiction for any changing regulations. Maybe they didn't change the date of the switch, but changed the timezone boundary on the map.

But, then I guess we might need to account for fractured societies and actually store some kind of organizational code for which belief system the event author adheres to? :-)


You jest, but there are three calendars in active daily use in close enough proximity to me that it is not unheard of for mistakes to happen. Especially in the evening, as not all calendars start the new day at the same hour!


To me that an UI/UX issue.

Internally everything is stored and handled in TAI (better than UTC as no discontinuity) and translated from/to something else for human consumption.

I.e. for instance your should have logic to figure out what TAI period corresponds to "next month's meetings" if that's what the user wants, which you apply immediately on user inputs and then forget about DST, time zones, etc. in the rest of the code and storage.

Another benefit is that if your user was in New York but is now in London it is trivial and well-constrained to adjust to local time.


No, it is not. It is because converting to UTC loses information that can't be retrieved.


Uh, no - meetings need to be stored with a timezone they were created in. This is how major calendar apps work.

In Apple Calendar you can enable advanced timezone settings and you get a timezone override option.


Some use cases really do require the local TZ offset be saved. Transforming everything to UTC wipes out that information.

An engineer in the US reviewing industrial measurements logged in a plant in Asia from a variety of sources is definitely going to encounter lots of events recorded in local time. It would be maddening for that engineer to have to review and resolve events from different time coordinates, especially if they are doing the review months or years later. It's best to accept that reality and adopt local time as the standard. Then you must record the TZ offset per UTC in any new system you create.


You mean you must record the timezone? Because the TZ offset can change throughout the year (e.g. due to daylight saving time).


Usually the TZ offset is enough. The use case is a guy reading notes and logs from multiple sources. All that guy needs is to see the local time at the time and place of the event. So that, for example, he can match up the time stamp on some computer recorded log with the time some human operator recorded, in local time, on a paper record.


And if you need a date, then represent it as a date and not as a time point.


And ifnyou're displaying it in the Ui give users a date format option where ISO is the choice.

I use ISO for everything and your software wrongly assuming I want a deranged lunatic date format based on some locale is not going to cut it.

Locale is ok as a first guess, but maybe allow users tho make that choice?


TAI is even better as it is continuous without leap seconds.


Even then it‘s ok :)


Proer tip: never use anything but unix timestamp until presentation.


This is great until someone asks whether a particular event happened before or after lunch.


I always felt the answer to this question is both, since there is always yesterday and tomorrow as far as lunch is concerned, so everything by definition is both before and after lunch. Perhaps the question is ill formed and needs to ask if the time was before, during or after lunch, during the day of the timestamp while defining what during means. That would have a more normal answer.


The question is clear.

You are obfuscating it, for your own entertainment.


It is unclear to me. It has been ever since I was a child. This is what happens with periodicity. There is no 1 lunch reference point when you just say lunch in this sort of question.


You're not alone, believe me, but one of the things you have to learn at some point is that for the vast majority of the population the question is perfectly clear. This is an example of the midwit meme, something like this:

IQ 55: it happened before lunch,

IQ 100: "lunch" isn't a time, lunch for whom? And which lunch? Their first ever lunch? Do babies even have lunch?

IQ 145: it happened before lunch.


Usually, people with higher IQs are the ones who have trouble with such things. There is a logical difference between “before lunch” and “before lunch that day”. This is similar to how higher IQ individuals see the Monty hall problem as having a 2/3 probability rather than a 1/2 probability in the famous version of the problem posed to Marilyn vos Savant. They are often derided as being idiots for not having “common sense”, even when their remarks are correct.

That said, IQ is considered obsolete given the theory of multiple intelligences. IQ only covers a subset of it.


There's no reliable way to map it back into the local time in the past, unless you also safe the UTC offset.


If you record them with some known UTC offset regardless of localtime (e.g. 0), you can convert to local time in the past.


The problem with that is you lose the localtime information, which you may want. Say you have recorded the localtime with the known UTC offset of 0, and that localtime is midnight UTC. Now you want to map it back to a localtime in the past. Ok, which localtime? Was it 8pm in NYC? Or was it 5pm in LA? Is the assumption that the localtime is wherever the user is right now, and is that a valid assumption? If the user has traveled to a different timezone, the time is now being converted to a localtime in the past that is different than it actually was when it happened.

edit: another commenter shared this link with an example: https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a...

I like their "Principle of preserving supplied data".


> If the user has traveled to a different timezone, the time is now being converted to a localtime in the past that is different than it actually was when it happened.

I consider this to be a desirable behavior.


For most cases I think that would be correct, but I will say if I am looking at my ATM withdrawals for a trip I made to San Francisco, I would like the time shown to be the SF time and not that of my local hometown, and vice versa if I'm in SF.


Even more proer tip: only use binary representations of variables until presented to the user.


Cloudist (https://www.cloudist.se) | Software Engineer (React/Next.js/Fullstack TypeScript) | Malmö, Sweden | Onsite/Hybrid

Cloudist helps partners to offer Green Cloud services to their customers. The product you'd be working on would be a portal backed by an API allowing for clients to spin up VMs, provision S3-compatible storage buckets etc. Think AWS Console and API, but of course in a smaller scale.

We're a small, boot-strapped, profitable startup with an interesting voyage ahead of us.

This is a full-time (i.e. non-contractor) position, and we require you to be able to commute into our Malmö office several days a week. You should have a permanent work permit in EU and proven experience working face-to-face in EU-based teams. I.e. we offer no work visa sponsorship.

Read more and apply at https://www.cloudist.se/full-stack-developer

Don't hesitate to contact me at thomas.lundstrom@cloudist.se if you have any questions.


Cloudist (https://www.cloudist.se) | Software Engineer (React/Fullstack TypeScript), Software Engineer (Backend TypeScript) | Malmö, Sweden | Onsite/Hybrid

Cloudist helps partners to offer Green Cloud services to their customers. The product you'd be working on would be a portal backed by an API allowing for clients to spin up VMs, provision S3-compatible storage buckets etc. Think AWS Console and API, but of course on a smaller scale.

We're a small, boot-strapped, profitable startup with an interesting voyage ahead of us.

This is a full-time (i.e. non-contractor) position, and we require you to be able to commute into our Malmö office several days a week. You should have a permanent work permit in EU and proven experience working face-to-face in EU-based teams.

Read more and apply at https://www.cloudist.se/full-stack-developer

Don't hesitate to contact me at thomas.lundstrom@cloudist.se if you have any questions.


Hmm. I logged on thru Google OAuth, and now I'm logged on as Alex. I've done the List Comprehension Python list filtering here: https://howtoxwithy.com/how-to/615701ba-4707-423d-a012-47943... but that one's written by "Alex", i.e. you.


Did you know lists have a .remove() ?

    >>> my_array = [1, 2, 3, 4, 5]
    >>> my_array.remove(1)
    >>> my_array
    [2, 3, 4, 5]


Seems that if you register with google Oauth the username is always Alex ... or at least for the two of us


That was an oversight on my part. If you sign out and sign back in I can edit the database to give you credit.


As a snus (ab)using Swede, I'd really prefer this packaging rather than the original ones.

Classy, Norway!


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: