[erlang-bugs] leap-second-enabled FreeBSD doesn't work right with R12B4 erts/emulator/beam/erl_time_sup.c; correction patch included

Kenji Rikitake kenji.rikitake@REDACTED
Sun Sep 14 03:41:11 CEST 2008


A patch to correct erlang:universaltime_to_localtime/1
for FreeBSD running leap-second-enabled timezone
by Kenji Rikitake <kenji.rikitake@REDACTED>
14-SEP-2008

* Summary

This patch fixes the time calculation problem of
FreeBSD 6.x and 7.x, which has the internal leap-second 
correction enabled.
This patch is tested with Erlang/OTP R12B-4 source distribution.

* Symptom

Without this patch,
erlang:localtime_to_universaltime/1
and
erlang:universaltime_to_localtime/1
are not symmetric and will break
calendar:local_time_to_universal_time_dst_1/1
and
httpd_util:rfc1123_date/1

* Example of symptom:

(under where local time is GMT + 9 hours)

1> erlang:localtime_to_universaltime({{2008,9,1},{12,0,0}}).
{{2008,9,1},{3,0,0}}
2> erlang:universaltime_to_localtime({{2008,9,1},{3,0,0}}).
{{2008,9,1},{11,59,37}}

(Note that as of September 1, 2008, TAI - UTC = 33 seconds.
UNIX time_t with TAI correction is 10 seconds ahead of UTC.
So the 23-second difference occurs when the leap-second
correction is NOT performed, as in the C function of
univ_to_local() in erts/emulator/beam/erl_time_sup.c)

* Workaround in this patch

This patch changes the operation of
erlang:universaltime_to_localtime/1
so that the "universaltime" is handled properly
with leap-year correction.
(Note: OS time_t is in TAI)

See FreeBSD man time2posix(3) and
/usr/src/lib/libc/stdtime/localtime.c
for the further details.

This patch will NOT affect a FreeBSD machine without
leap-year correction; posix2time() will do nothing
in such a situation. (NOT tested though)

* Caveats, TODO and suggestions

There is no portable way to do this among UNIX-derived OSes

HAVE_POSIX2TIME should be set by configure

A Linux patch for leap-second supported systems is highly desired
(I found posix2time() is also available on Linux, but I'm not sure)

Should I rather do this using timegm(3) and throw away
the rather naive computation algorithm in univ_to_local()?
(Note that this is not necessarily portable either)

* How to apply this patch

Apply this at Erlang R12B4 source tree's directory under:
erts/emulator/beam

--- erl_time_sup.c.FCS	2008-04-07 22:57:50.000000000 +0900
+++ erl_time_sup.c	2008-09-14 09:56:10.000000000 +0900
@@ -71,6 +71,10 @@
 **
 */
 
+/* FreeBSD internal leap year correction function */
+/* define this for FreeBSD 6.x and 7.x */
+#define HAVE_POSIX2TIME
+
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
@@ -686,6 +690,18 @@
     
     the_clock = *second + 60 * (*minute + 60 * (*hour + 24 *
                                             gregday(*year, *month, *day)));
+#ifdef HAVE_POSIX2TIME
+    /* 
+     * leap-second correction performed 
+     * if system is configured so;
+     * do nothing if not
+     * See FreeBSD 6.x and 7.x
+     * /usr/src/lib/libc/stdtime/localtime.c
+     * for the details
+     */
+    the_clock = posix2time(the_clock);
+#endif
+
 #ifdef HAVE_LOCALTIME_R
     localtime_r(&the_clock, (tm = &tmbuf));
 #else





More information about the erlang-bugs mailing list