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.