Glib seems to circumvent the UN*X system time routines and thereby misses the leap seconds

After I thought the crystal in my self-tinkered sensor concentrator broke,
I made my own zoneinfo file, that does not know leap seconds or DST (it just knows SI-seconds and 24hrs days and 60secs minutes)…

The UN*X (archlinux) system time functions say this now:

> TZ=UTC date -d "2017-01-01 - 1 second"
Sat Dec 31 23:59:60 UTC 2016
> TZ=UTC date -d "2017-01-01 - 1 second" +%s
> date -d@1483228825
Sun Jan  1 00:00:35 TAI 2017
> TZ=UTC date -d@1483228825
Sat Dec 31 23:59:59 UTC 2016
> date -d@1483228826
Sun Jan  1 00:00:36 TAI 2017
> TZ=UTC date -d@1483228826
Sat Dec 31 23:59:60 UTC 2016
> date -d@1483228827
Sun Jan  1 00:00:37 TAI 2017
> TZ=UTC date -d@1483228827
Sun Jan  1 00:00:00 UTC 2017

But g_date_time_new_from_unix_local and/or g_date_time_get_second act like these 27 leap seconds never happened…

Why is that?

PS: Javascript has a problem with my TAI zoneinfo, too.
PPS: fetchmail and s-mailx and exim already treat such timezones properly…
PPPS: gmime (and thereby balsa) cannot fix it, because: gmime relies on glib.


There’s some explanation in the documentation of g_date_time_new_from_iso8601():

Note that as GDateTime “is oblivious to leap seconds”, leap seconds information in an ISO-8601 string will be ignored, so a 23:59:60 time would be parsed as 23:59:59 .

That seems like a questionable choice to me, but I didn’t know about it and haven’t thought about it until now…

questionable choice

I concur… :rofl: (taken from: Catch Me If You Can)

I wonder why someone would break down “seconds since 1970” to “second/minute/hour/day/month/year” with her/his own code, instead of using the system function (like gmtime(3) or localtime(3)…)… It is like inventing the wheel again every time before entering a train…

Is it because of Windows? I mean: Does Windows have no system function for that? But then we could still use the UN*X system functions on UN**Xoid systems and offer some soopa special code for Windows…

Hopefully I can explain the choice so it doesn’t seem so questionable. GDateTime represents wall-clock time in a particular time zone. (“Wall-clock time” is also called “plain time”, “floating time”, or confusingly “local time” but that can mean other things too. It represents the time actually visible on the clock on your wall.)

Wall-clocks don’t have 61 seconds, so that’s why the :60 is dropped to :59.

It sounds like what you want is g_get_real_time() which gives you the “exact” time in microseconds elapsed since the Unix epoch (but which I now see is confusingly documented as returning wall-clock time)

However that probably also does not correctly take leap seconds into account despite the custom TAI zone info, because the Unix clock does not do so either. There are always 86400 Unix seconds in a day, even days with leap seconds that are supposed to have 86401 actual seconds. There’s more info and links in this Stack Overflow post.

1 Like

here i do not concur…

> TZ=/usr/share/zoneinfo-posix/right/UTC date -d 2017-01-01 +%s
> TZ=/usr/share/zoneinfo-posix/right/UTC date -d 2016-12-31 +%s
> expr 1483228827 - 1483142426

so glib deliberately does not want to comply to POSIX and use some “wall clock standard”?

could we add a time_t g_get_posix_time(const char * const zoneinfo_file_name, const struct tm * t)?

or just a g_gmtime and g_localtime?

I mean, sure, that’s what your custom zoneinfo file says, but mine still says the day of 2016-12-31 lasted 86400 seconds. GLib’s exact time corresponds with POSIX time, and POSIX time ignores leap seconds, it says so right there in the standard. I suspect, but am not certain, that if you actually measured the real time with a stopwatch in between Unix time 1483228827 and Unix time 1483142426, in which a leap second was inserted, it would last 86402 SI seconds, not 86401.

Wall-clock time isn’t a standard; it’s a different data structure, meant for a different purpose, than exact time. I might be wrong, but it sounds like what you want is exact time, (or at least, as exact as it can get with POSIX), which is given by g_get_real_time() (despite that function’s documentation claiming it returns wall-clock time, which I don’t think is correct). So don’t use GDateTime, which represents wall-clock time. Insisting that you need GDateTime is like insisting that you need GSList but complaining about the random access performance.

Now as for the question is why your custom zoneinfo file is not being picked up … that I don’t know.


GLib’s exact time corresponds with POSIX time

The mktime(3) man page says: “POSIX.1-2001”. I just do not understand, why on GLib time scale a second is sometimes 2 SI seconds long…

Now as for the question is why your custom zoneinfo file is not being picked up … that I don’t know.

can I see the source code somewhere without downloading everything? i mean: why can date(1) understand my zoneinfo file, but GLib doesn’t?

That’s not GLib. It’s POSIX. In the mktime(3) man page, it does say the seconds field of struct tm is allowed to be 60, but that doesn’t mean gmtime() will fill it in correctly during a leap second.

Yes, you can browse it at our GitLab instance: glib · main · GNOME / GLib · GitLab

But how does date(1) do it (see my initial post)…?

Presumably that’s because of your custom zoneinfo file? That doesn’t happen on my system.


because of your custom zoneinfo

ok… one last try: presumably that is because of GLib’s custom interpretation of the POSIX zoneinfo file and the POSIX time in general?