Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Designing a REST API: Unix Time vs. ISO-8601 (2013) (nickb.dev)
42 points by ducaale on March 30, 2022 | hide | past | favorite | 50 comments


Unix time is not unambiguous. It is linked to UTC, so occasionally there are leap seconds, and there isn’t a standard format for these (two seconds == one second, or skip a second)[1]. TAI is a better format, but turns out the common TAI libraries just code the TAI offset from Unix time.

[1] https://geometrian.com/programming/reference/timestds/index....


For nearly all web-based apps (i.e., most REST API clients), missing a single second (either permanently, or for a period of time until NTP catches up the system clock) is so trivial as to be meaningless. Even things like action games or TOTP won't mind about a single second.

The only place where I can envision this being a potential problem might be with stock trading, but HFT or other low-latency trading wouldn't be done through a REST API or web browser anyway.

Meanwhile, with UNIX time, you gain a mostly unambiguous, cross-platform way of dealing with dates/times with just an integer, easy math and comparisons (such as: this integer timestamp is > another, so it occurred after), and zero parsing or storage of text strings. That is a huge win in practical API design, especially when dealing with thousands or millions of events, and using an integer datatype in a database instead of a text field is a significant win, too, in terms of storage and indexing.

With that said, standards are nice, especially when dealing with an API that might talk to many different types of clients, but a text-based format like ISO-8601 probably isn't an optimal solution for most use cases.


Google started doing leap second smearing [1] in 2008, which basically slows down each second over a 24-hour period, noon to noon UTC.

ntpd also supports this [2], though I'm not sure how popular it is in practice. Anyone making use of this?

[1] https://developers.google.com/time/smear

[2] https://docs.ntpsec.org/latest/leapsmear.html


How does that make sense? Unix time is basically a stopwatch that someone started a long time ago. How would a leap second matter?


Naw that would make way too much sense. Instead, unix time ticks backwards 1 second to sync up with UTC:

    099.75
    100.00
    100.25
    100.50
    100.75
    100.00
    100.25
    100.50
    100.75
    101.00
Maybe some day we’ll get rid of this collective brain damage: https://en.wikipedia.org/wiki/Leap_second#International_prop...


> Naw that would make way too much sense. Instead, unix time ticks backwards 1 second to sync up with UTC:

Doesn't that mean that UNIX time is in fact a stopwatch, but to express it in UTC you need to factor in UTC's quirks such as its leap seconds?


No. Like I said, that would make way too much sense.

The hardware RTC on your motherboard is a stopwatch. When a leap second occurs, your system time will be set 1 second backwards which is also 1 second less than what the RTC reports. Then, the new fuckered time will be written to the RTC so it stops acting as a stopwatch and instead tracks unix time.

An application that reads the system unix time 4 times a second (using a monotonic clock for the 250ms delay) and prints it will observe a negative duration in unix time as seen in my previous comment.

> to express it in UTC you need to factor in UTC's quirks such as its leap seconds

Oh that would make unix time so much more useful. But no, the UTC quirk is incorporated into unix time the instant a leap second happen as if some nutjob logged into all your servers and changed each clock manually.


Dear God.


Because unix time isn't a stopwatch that someone started a long time ago. Leap seconds change unix time because unix time is tied to UTC.


I'm not really following. How does the fact that Unix timestamps are in terms of UTC affect whether leap seconds get incorporated into the timestamp or not? Do leap seconds work differently in UTC or something?


Unix timestamp assumes there are exactly 86400 seconds in a day. Or, in other words, if your timestamp is a multiple of 86400, it's midnight UTC.

There are not alway 86400s in 1 day. Midnight is not a whole number of multiples of 86400 after Jan 1st 1970.


> There are not alway 86400s in 1 day. Midnight is not a whole number of multiples of 86400 after Jan 1st 1970.

Isn't that an issue with the format you want to convert UNIX time to ?

I mean, UNIX time is quite clearly and unambiguously defined as the number of seconds that passed since January 1st 1970. How are UTC's leap seconds any relevant?


> I mean, UNIX time is quite clearly and unambiguously defined as the number of seconds that passed since January 1st 1970.

It's not though. Unix time is not monotonic. It goes backwards sometimes.


Specifically unix timestamp is (number of days since 1970-01-01 × 86400) + (seconds since midnight). The difference arises from the fact that in utc some days are 86401 seconds long.

Another way of viewing it is that unix timestamp is seconds since 1970-01-01 minus number of leap seconds that have passed.


> Do leap seconds work differently in UTC or something?

Leap seconds exist in UTC, that's the entire thing.

A leap second getting inserted (which has always been the case so far, though it may eventually change) means a UTC day ends on 23:59:60, which as far as UTC is concerned is perfectly fine, nothing wrong with a minute having 61 seconds.

UNIX time though? UNIX time is (86400 * days since epoch) + seconds since midnight.

23:59:60 is 86400, so on the last second of day X you're at 86400 * X + 86400, and on the next second (the first of day X+1) you're at 86400 * (X+1) + 0.

Which is the same value. And thus one second repeats.


> If a leap second is to be inserted, then in most Unix-like systems the OS kernel just steps the time back by 1 second at the beginning of the leap second, so the last second of the UTC day is repeated and thus duplicate timestamps can occur.

So certain unix timestamp can represent two different points in time, the last normal second of the day or the leap second that happened after it. This makes (certain) unix timestamps ambiguous.


UNIX time is not actually a stopwatch, it's defined as 86400 seconds per day elapsed since epoch, plus the number of seconds elapsed since the last midnight (in essence it matches UTC seconds from 1970).

Thus UNIX time is at least 27 seconds late (because there have been 27 seconds since 1972).


Because of leap seconds, Unix time is also only valid for leap-seconds that the program knows about: in effect, only dates set in the past before the program (or system) was last updated to take new leap seconds into account.


If you need to translate between Unix time and UTC (or something geodesic like UT1), you'll be at most one second off. The difference due to leap seconds only accumulates if you need to translate something civil or geodesic (UTC, UT1, Unix time) to TAI.


also, unixtime just describes the time till the start of measurement of the time. it does not describe the organisatorial/socetial defined time which i currently "experience". like, leap years, timezones, sommertime or not, the new global dictator which will emerge in 500 years which defines the time beginning with his birth


I find this article to give a good overview of how leap seconds are handled on Unix:

http://www.madore.org/~david/computers/unix-leap-seconds.htm...


There's also RFC 3339[1] which is, IMO, a bit better. The RFC is readily readable, unlike an ISO standard, and the RFC is — mostly — more restrictive.

ISO is fun up until you have to parse "2022-089". Yes, that's a valid ISO date. And it's in March. (And yes, I've seen that used in the wild, though I don't know why anyone would ever choose that format.)

[1]: https://datatracker.ietf.org/doc/html/rfc3339


Unix Time should be an implementation detail. ISO-8601 is IMO the preferred format for APIs.


JSON needs to have a timestamp type. Parsers should automatically convert them to/from native language timestamp objects. Human readable is preferred, but really the critical aspect is to make the JSON self-describing. If timestamps are self-describing, any smart editor can display them properly.


JSON doesn't have types like that so that doesn't make sense. It supports a few simple primitives and that's what makes it extensible and gives it it's power. Types like timestamps should come from the language or library that produces JSON only.

https://www.json.org/


Semantically timestamp is a product type imho, so the logical representation in JSON would be with an object: {"year" 2022, "month": 4, "day": 1, ...etc}. The fact that nobody does that and instead serialize it to ISO-style string is telling about json.


> The fact that nobody does that and instead serialize it to ISO-style string is telling about json.

Tell me more about that. I'm not sure I grasp what it is telling about JSON?


I see it as a sign that JSON is not that great for structured data if people prefer to pack their datetime structure into a string rather than the more native object format.


Oh, gotcha. Well, I definitely agree it would make more sense for it to be an object like you mentioned but I think it's probably more explainable by the fact there is native support for ISO date / time strings in most programming languages, making it just as easy to parse a date or time from a string value and having the added advantage of reducing the size of the payload on the wire. I could be wrong


JavaScript has a date type. It is perfectly reasonable to expect JavaScript Object Notation to have a date type.


Wait until you visit the link and read what “object” means in JSON, especially the part about remaining interchangeable with all programming languages


"All" programming languages have some concept of a timestamp, or at the very least can manage a coherent mapping. Adding timestamp to JSON would introduce no portability issues. It would reduce portability issues by standardizing a commonly used data type.

"My programming language doesn't have timestamps" is not a real problem.

"Ten thousand stupid date formats which are all ambiguous with either numbers or strings" is an actual problem that people bang their heads into every day.


> Adding timestamp to JSON . . .

What are you talking about? JSON is a format for exchanging data of any kind. It doesn't have types beyond a set of primitives to that it can remain as a _notation_ that allows you to pass any type you define and want to send.

Nothing is stopping any library or language from implementing an object or String for dates or times (or both) and tons of them have done so.

It wouldn't be JSON's place at all to start defining anything like that.


Nonsense. JSON (or "JSON++") can define any arbitrary primitives. Someone already made the arbitrary decision to have boolean values instead of "true" and "false" strings; having timestamps is merely another arbitrary decision.

You seem to believe that the primitives in JSON are some sort of platonically pure form. They were merely a choice, and a that choice could be improved.


CBOR has four defined timestamp formats---see https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml


.NET has no trouble going between ISO-8601 and the native DateTime type.


If you have a priori knowledge of the schema (say, mapping to/from classes) you can convert anything. You don't even need something like JSON, you could just have a binary format and IDL.

JSON self-describes booleans, numbers, strings, arrays, objects, and null. This is especially convenient when working with dynamic or ambiguous structures, and working in dynamically typed languages. Timestamp is sufficiently common and useful that it should be added to that list.

If you mean ".NET parser pattern matches strings and converts them dynamically" - that's the same horrible behavior yaml parsers have and it causes endless trouble. Imagine parsing titles of posts and some clever author makes a title that matches the timestamp format.


The .NET parser will only parse ISO-8601 to a DateTime if that's the type you tell it to accept. If you tell it to accept a string, it won't try to do anything funny no matter what that string may look like.


When .Net just started, they would deserialzie datetime to... a string which looked something like `DateTime\(2007-12-10\)`.

10-15 years later I'm still baffled by that early decision (and glad it's been fixed since then)


unixtime/microseconds is not necessarily a acute reflection for you to say what i year/month/day/hour/minute/second i am experiencing from an societal standpoint.

and that is important in realworld applications.


> A sample of 20 APIs yielded nearly a 50/50 split.

Is it still a 50/50 split today? I suspect ISO 8601 has grown to become the standard.


Public APIs maybe. Internal? I'm not so sure. Since JSON doesn't have a time type, an ISO date field always requires validation and there are plenty of edge cases to consider (e.g. do you want to accept bare/naive datetimes, do you want to require all parts to be present, do you allow week dates, etc).

The biggest advantage of ISO 8601 is probably that you can also use it to represent dates and/or times rather than only datetimes but this can result in unnecessary ambiguity (e.g. if you decide to split the datetime into a date and a time field and make assumptions about the timezone).


I’m quite surprised that Unix time is so common. My anecdotal experience with dozens of public and internal APIs over 20 years of development is that the most common format is local time followed by ISO. I actually have almost never seen Unix time.


If I had a penny for every time I assume an API takes Unix time in milliseconds or seconds and it turns out to be the other...


Local time? In a public API?


Programmers are lazy. I've seen more than my fair share of the default behavior of a language like Java implemented. Which usually means just making a system call for the current time and will return the time in whatever time zone the system happens to be set for.


> "Unix time is completely unambiguous."

Looks like someone hasn't had to deal with data from multiple different time zones processed by code written by different developers over several years!

Unix time could be unambiguous, but it is not in practice. If it has been unambiguous for you, congratulations!

Use ISO style dates if you don't want to spend the rest of your life explaining what a date actually means.


> data from multiple different time zones processed by code written by different developers over several years!

This feels strongly an argument FOR unix timestamps. Simply a number, the biggest mess up is seconds/millis. This order of magnitude difference is not that hard to disambiguate.


Unix timestamps have a convention of being an offset from Jan 1 1970 00:00. But is that Jan 1 1970 GMT or UTC or local time? There is a right answer here! But! Did all the developers do the right thing? Was the default implementation correct?

---

What I'm saying is - in your json document, you see a number and you rely on a convention to decode that number. The number has no way to tell you anything about what the number actually means. The ISO standard does. People could still mess it up, but I feel like the people who use the ISO standard care a lot more than the people who use the Unix standard.


> Did all the developers do the right thing?

"The right thing" is, for example, simply `System.currentTimeMillis()` in Java. I don't have to think about what 0 means. All I need to know is there's a mapping from an instant to a number.

This representation is arguably closer to the essense of time. Barring relativistic effects, it's just an affine line. Dates and timezones are artificial structure that we put on this line.




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

Search: