9

I read many, many posts about Unix time and many say that a day is 86400 seconds.

But pages like this talk about leap seconds. And this made me confused. And I read that Unix time is based on UTC, and all I can understand is that the different between UTC and TAI is the leap seconds, so then Unix must support leap, otherwise why not saying based on TAI instead of UTC?

To confuse myself more, I tried to see what Windows does, and the answers I found is that it does not count leap seconds, but it says based on UTC, and again confusing, as why saying UTC if it is not counting leap?

Anyway, I wanted to ask exactly on how should one convert an integer amount of seconds to exact date in Unix?

Kusalananda
  • 333,661
Okoba
  • 93
  • 1
    Does this answer your question? Leap seconds and date – muru Oct 14 '23 at 16:20
  • @MarcusMüller so it starts from "00:00:00 UTC on Thursday, 1 January 1970" but not working as UTC? I am now confused, then what is the difference between TAI and Unix time? just the epoch? – Okoba Oct 14 '23 at 16:28
  • 1
    UTC is something completely different altogether: It defines what time it is – not just how many seconds since some common event. "It's fourteen million two hundred thousand twenty six seconds since epoch" is less useful than saying "it's 9:12 in the morning here, and today's the sixth of June", for example, in many cases. – Marcus Müller Oct 14 '23 at 16:35
  • Related: https://unix.stackexchange.com/q/283164/88378 Astronomer Steve Allen has a lot of info on this topic, eg https://www.ucolick.org/~sla/leapsecs/picktwo.html & https://www.ucolick.org/~sla/leapsecs/epochtime.html – PM 2Ring Oct 16 '23 at 10:21

3 Answers3

23

I read many, many posts about Unix time and many say that a day is 86400 seconds.

That's the definition, yes.

But pages like this talk about leap seconds. And this made me confused.

You're not the only one. It's a hilarious mess.

And I read that Unix time is based on UTC

It is, see below.

and all I can understand is that the different between UTC and TAI is the leap seconds

Yes.

so then Unix must support leap

It doesn't. It effectively closes its eyes and refuses to listen to any talk about such awkward and impractical technicalities.

The POSIX definition of "seconds since the epoch" is based on the broken-down UTC time, explicitly assuming that all days are 86400 seconds long:

4.15 Seconds Since the Epoch

A value that approximates the number of seconds that have elapsed since the Epoch. A Coordinated Universal Time [UTC] name (specified in terms of seconds (tm_sec), minutes (tm_min), hours (tm_hour), days since January 1 of the year (tm_yday), and calendar year minus 1900 (tm_year)) is related to a time represented as seconds since the Epoch, according to the expression below.

If the year is <1970 or the value is negative, the relationship is undefined. If the year is >=1970 and the value is non-negative, the value is related to a Coordinated Universal Time name according to the C-language expression, where tm_sec, tm_min, tm_hour, tm_yday, and tm_year are all integer types:

tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
    (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
    ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400

The relationship between the actual time of day and the current value for seconds since the Epoch is unspecified.

How any changes to the value of seconds since the Epoch are made to align to a desired relationship with the current actual time is implementation-defined. As represented in seconds since the Epoch, each and every day shall be accounted for by exactly 86400 seconds.

(The odd handling of tm_year is to account for leap days; the divisions are truncating integer divisions.)

The rationale part says admits directly to ignoring leap seconds:

Coordinated Universal Time (UTC) includes leap seconds. However, in POSIX time (seconds since the Epoch), leap seconds are ignored (not applied) to provide an easy and compatible method of computing time differences. Broken-down POSIX time is therefore not necessarily UTC, despite its appearance.


The expression above means that when a leap second is inserted, the "seconds since the epoch" repeats a full second:

UTC 1972-06-30 23:59:59 = 78796799 seconds since epoch
UTC 1972-06-30 23:59:60 = 78796800 seconds since epoch
UTC 1972-07-01 00:00:00 = 78796800 seconds since epoch
UTC 1972-07-01 00:00:01 = 78796801 seconds since epoch

Which means that either those "seconds" since the epoch aren't all (physically) the same length, or the epoch itself in effect "moves". Take your pick.

  • As above, that one second is two (physical, SI / UTC) seconds long, so clearly they're not all the same length.

  • The epoch "moving" is what follows if you take the "all days are 86400 seconds" definition, assume constant-length SI seconds and work back on that. (That is, since UTC 1972-07-01 00:00:00 is 78796800 SI seconds after UTC 1970-00-01 00:00:01, that must be the effective epoch at that time.)

Well, they did hedge by saying "approximates".

Also, this is one of those cases where a simple but exact solution just doesn't exist. You get to pick any two good things out of three and have to put up with either

  • a) days of variable length (in seconds);
  • b) seconds that themselves vary in length; or
  • c) a date system that ends up getting out of synch with the Sun.

POSIX rejects (a) for simplicity of date calculations, but otherwise matches UTC to match civil time, hence rejecting (c) and choosing to accept downside (b). Simplicity of calculations is explicitly mentioned in the rationale:

The topic of whether seconds since the Epoch should account for leap seconds has been debated on a number of occasions, and each time consensus was reached (with acknowledged dissent each time) that the majority of users are best served by treating all days identically. (That is, the majority of applications were judged to assume a single length-as measured in seconds since the Epoch-for all days. Thus, leap seconds are not applied to seconds since the Epoch.)

(The sentence "The relationship between the actual time of day and the current value for seconds since the Epoch is unspecified." is weird in itself, given UTC is "the actual time of day" for pretty much all practical purposes, and the definition above relies on UTC. I'm not sure what that refers to, but I think it just means to say that the system clock is not required to be accurate. And well, without external synchronization, most computer clocks aren't.

Similarly, "Broken-down POSIX time is therefore not necessarily UTC, despite its appearance." in the rationale part looks odd, but would apply at the moment of a leap second. Otherwise the given equivalence seems to mean broken-down POSIX time is UTC.)


But don't rely on me getting it right, since smarter people have written enough about it.


Anyway, I wanted to ask exactly on how should one convert an integer amount of seconds to exact date in Unix?

Depends on what seconds, exactly, those are...

If it's Unix time, divide by 86400 to get the number of days, and then follow the usual rules regarding variable-length months and leap days and timezones.

Or rather, call localtime() or gmtime() to do that for you.

If it's some other amount of seconds, use some library that can deal with what ever it is you have.

ilkkachu
  • 138,973
  • Read in context, it is just about possible that "actual time of day" means something along the lines of "local civil time, accounting for time zones, DST, and all the other political nonsense." Or, to put it another way, "the time that a non-technical human using the computer would give in response to a generic 'What time is it?' query, without any of this UTC/leap second/time zone/etc. gobbledygook." – Kevin Oct 15 '23 at 22:32
  • What a great text about time, and it is heartwarming to see that I am not alone in being puzzled by this situation. Thank you very much. – Okoba Oct 16 '23 at 10:26
  • @Kevin, perhaps that too, but I think timezones are mentioned elsewhere in the standard. Re-reading the rationale, it looks more to me that they mean that the clock doesn't need to be accurate, it says: "... most systems are probably not synchronized to any standard time reference. Therefore, it is inappropriate to require that a time represented as seconds since the Epoch precisely represent the number of seconds between the referenced time and the Epoch." (of course NTP and constantly-connected systems are much more common now than back in the day) – ilkkachu Oct 16 '23 at 14:45
12

You're confusing multiple concepts. UNIX time is (from sufficient height) a second counter, that is just a local notion. In the end, someone carried a clock to you and said "according to this nice clock, it's now so and so many seconds since 1.1.1970", and you go "ok, then its now so and so many seconds since 1.1.1970" and continue counting seconds. That's OK for many "household" usages of time keeping, like, say, storing when you last changed your diary document. TAI is also just a second counter, but it's a coordinated one, meaning that it's not just a local counting of time, but the average of many atomic clocks.

UTC is something completely different altogether: It defines what time it is – not just how many seconds since some common event.

"It's fourteen million two hundred thousand twenty six seconds since epoch" is less useful than saying "it's 9:12 in the morning here, and today's the sixth of June", for example, in many cases.


To be clear: "UNIX time" is simply the number of seconds passed since a specific event (Epoch). If you had a perfect metronome that ticked once per second, and you counted the ticks since that date, that is UNIX time. (If it weren't for the fact this counter is actually derived from UTC in a way that effectively moves that Epoch forward a second every time UTC inserts a leap second.)

Now, your confusion stems from the fact that e.g. 1697300527 (which is the UNIX time a few seconds ago) isn't a very useful time for a human. You will want to convert this second count to a human-readable datetime (e.g., Sat. 14. Oct. 2023 18:22:01).

Time conversions of course have to take leap years, leap seconds, time zones and other corrections into consideration. That means the conversion from UNIX time to a UTC time or any other time representation is not necessarily smooth, continuous, or even unambiguous. (For example: There might be more than one UNIX time stamp that corresponds to 3:15 am on the day that daylight savings time ends in your time zone.)

That's it. While you can always "easily and unambigously" say "it is now so and so many seconds since Epoch", simply by counting the seconds since then (which is what UNIX time is), the conversion to a local time (or coordinated time) representation for human purposes can be non-monotonic.

Anyway, I wanted to ask exactly on how should one convert an integer amount of seconds to exact date in Unix?

By using the timezone information your platform has. Chris Davies proposes to use date, which I agree with. Any reasonable programming language¹ has access to a tzinfo database.


¹ C: ctime(…), C++: std::chrono, Python: python -c 'import datetime;print(datetime.datetime.now())', Perl, Haskell, …)

  • So can we say that leap second, is a conversation note for formatting seconds to human readable date time? like time zone? I can use standard libraries, but my question is more about "What is happening?" – Okoba Oct 14 '23 at 16:44
  • To be clear, on this post: https://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux, there is comment as "Leap seconds were introduced in 1972. So there is none between 1601 and 1970 and thus irrelevant in this conversion." and from what I understand from your answer, it is not right to think about leap second, while converting between UNIXTIME and FILETIME as the both are just monotonic counters after an specific time in UTC time system. Correct? – Okoba Oct 14 '23 at 16:53
  • 4
    "To be clear: "UNIX time" is simply the number of seconds passed since a specific event (0:00 on the first of January 1970). There's no ambiguity there anywhere." -- well, except that there is, namely the thing about which exact moment of time 1970-01-01 00:00 is. Leap seconds can make days differ in length (and we're not talking about daylight saving here), but POSIX defines the "seconds since epoch" as counting exactly 86400 seconds per day. – ilkkachu Oct 14 '23 at 17:47
  • And really, it defines seconds since the epoch being "A value that approximates the number of seconds that have elapsed since the Epoch." and gives an expression to convert UTC time into "seconds since epoch". – ilkkachu Oct 14 '23 at 17:49
  • I am puzzled. UNIXTIME and FILETIME both do not count leap seconds, and as far as I understand and you said to me, are counters and not human readable time. And leap seconds are for human readable times when we talk about days and months. So is it important to consider leap seconds when we convert from UNIXTIME and FILETIME or the other way around? If yes, why? and if no, why you said I am not correct? – Okoba Oct 14 '23 at 17:59
  • "Filetime" is not a universal concept, @Okoba. It's whatever the individual file system defines it to be, and/or what the operating system fills in there. Windows' file system abstraction layer is different than the one of Linux, and I'm sure there's also completely different notions of time of files on other operating systems with other notions of time. – Marcus Müller Oct 14 '23 at 18:00
  • Sorry I thought it is clear that I mean Windows FILETIME as I linked the question about it. To be clear, I mean FILETIME as https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime?redirectedfrom=MSDN and UNITXTIME as Unix time, the one I asked question about. For these, can I say they are counters and leap seconds are not important for them? – Okoba Oct 14 '23 at 18:06
  • I really don't know the internals of Windows, @Okoba, and can't comment on that. – Marcus Müller Oct 14 '23 at 18:06
  • Tbh I was very surprised to find I couldn't invert a leap second date. I had assumed that on occasion there were 86401 seconds/day in the UNIX timezone world – Chris Davies Oct 14 '23 at 18:19
  • @ChrisDavies I'll say it's at the very least a distinct idea to basically redefine your reference point every once in a while instead of defining rules for conversion. – Marcus Müller Oct 14 '23 at 18:22
  • Now, regardless of what I wrote above, this is a subject I've lost my head in before, so I might just be confused again. I think I've seen some relatively convincing-sounding post on the whole disaster before. What I was able to find now were this SE Q&A https://stackoverflow.com/questions/16539436/unix-time-and-leap-seconds and this post http://www.madore.org/~david/computers/unix-leap-seconds.html . – ilkkachu Oct 14 '23 at 18:24
  • 4
    @MarcusMüller, note that it's not actually defined as redefining the reference point. It's defined as a number you get when you do a particular calculation on the broken-down UTC date and time. A calculation that is obvious, appears correct, and produces a practical and useful result, but happens to close its eyes and go la-la-la at obscure impractical thingies like "leap seconds". (The reference point getting "moved" is just an emergent result of taking the "seconds since the epoch" literally and applying that to the definition.) – ilkkachu Oct 14 '23 at 18:28
  • @ilkkachu exactly. That's what I meant with "basically redefine". I mean, especially in terms of what that means for UNIX time differences, it's um, original. – Marcus Müller Oct 14 '23 at 18:30
  • @ilkkachu any way, tried to defuse the wording of my answer. – Marcus Müller Oct 14 '23 at 18:38
  • 1
    @Okoba You can prove to yourself that Unix time doesn't take leap seconds into account by noticing that the first second of next year can be determined without taking them into consideration. Running TZ=UTC date --date @$(perl -e '$seconds += 86400 * ($_ % 4 ? 365 : 366) for 1970 .. 2023; print $seconds') '+%F %T %z (%Z)' produces 2024-01-01 00:00:00 +0000 (UTC) on Linux, as does running TZ=UTC date -r $(perl -e '$seconds += 86400 * ($_ % 4 ? 365 : 366) for 1970 .. 2023; print $seconds') '+%F %T %z (%Z)' on BSD (including MacOS). – tchrist Oct 15 '23 at 22:38
  • @ChrisDavies, Unix time doesn't have days, or years, or months, or any other unit besides the second. – Mark Oct 17 '23 at 02:08
  • @Mark. Yes, that's right – Chris Davies Oct 17 '23 at 08:42
3

If you have a suitable version of date you can use its built-in capability:

date
Sat Oct 14 17:17:59 BST 2023

date +'%s' 1697300279

date --date '@1697300279' Sat Oct 14 17:17:59 BST 2023

date --date '@1697300279' +'%Y-%m-%d %H:%M:%S' 2023-10-14 17:17:59

Chris Davies
  • 116,213
  • 16
  • 160
  • 287