[R-SIG-Mac] Formatting of time zone for POSIXct

Simon Urbanek simon.urbanek at math.uni-augsburg.de
Wed Jan 19 22:54:13 CET 2005


Don,

thanks for your report.

On Jan 19, 2005, at 12:41 PM, Don MacQueen wrote:

> I'm encountering a problem formatting POSIXct objects in R 2.0.1 on OS 
> X.
>
> For reference, on a Solaris system, R 2.0.1 (2004-11-15), formatting 
> is correct:
>
>>  Sys.time()
> [1] "2005-01-19 09:12:33 PST"
>>  format(Sys.time(),'%H:%M %Z')
> [1] "09:12 PST"
>
>
> On Mac OS X, however,
>
> R 2.0.1 Patched 2005-01-19
>
>>  Sys.time()
> [1] "2005-01-19 09:18:27 PST"
>>  format(Sys.time(),'%H:%M %Z')
> [1] "09:18 P"

The man pages says:
    usetz: logical.  Should the timezone be appended to the output? This
           is used in printing time, and as a workaround for problems
           with using '"%Z"' on most Linux systems.

so after reading that, you get the correct result:

 > format(Sys.time(),'%H:%M',usetz=TRUE)
[1] "15:57 EST"

Now, the reason why I'm CCing this to R-devel is that in fact the 
datetime.c is somewhat weird for non-GlibC2 systems as tm.tm_zone is 
not initialized at all, which I suspect is a bug. Either the docs 
should state that %Z should not be used at all or I'd propose the 
following patch to make it work (warning, it's a patch against 
R-devel):

Index: src/main/datetime.c
===================================================================
--- src/main/datetime.c (revision 32715)
+++ src/main/datetime.c (working copy)
@@ -581,15 +581,8 @@
         error("invalid `usetz' argument");
      tz = getAttrib(x, install("tzone"));

-    /* workaround for glibc bug in strftime */
-#if defined HAVE_GLIBC2
-#ifdef __USE_BSD
-    tm.tm_zone = NULL;
-#else
-    tm.__tm_zone = NULL;
-#endif
-#endif
-
+       memset(&tm, 0, sizeof(tm));
+
      /* coerce fields to integer, find length of longest one */
      for(i = 0; i < 9; i++) {
         nlen[i] = LENGTH(VECTOR_ELT(x, i));

This just zeroes out tm before use - it should also fix the problems on 
Linux. Just in case I overlooked something and it's not feasible to 
zero out the struct tm (e.g. if the size may be unknown), then the 
following, more paranoid patch could be used:

Index: src/main/datetime.c
===================================================================
--- src/main/datetime.c (revision 32715)
+++ src/main/datetime.c (working copy)
@@ -588,7 +588,11 @@
  #else
      tm.__tm_zone = NULL;
  #endif
+#else
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+    tm.tm_zone = NULL;
  #endif
+#endif

      /* coerce fields to integer, find length of longest one */
      for(i = 0; i < 9; i++) {
Index: configure.ac
===================================================================
--- configure.ac        (revision 32715)
+++ configure.ac        (working copy)
@@ -551,7 +551,7 @@
    fpu_control.h grp.h ieee754.h ieeefp.h limits.h locale.h \
    netdb.h netinet/in.h pwd.h strings.h \
    sys/param.h sys/select.h sys/socket.h sys/stat.h sys/time.h \
-  sys/times.h sys/utsname.h unistd.h)
+  sys/times.h sys/utsname.h time.h unistd.h)
  ## </NOTE>
  ## <NOTE>
  ## These are ANSI C headers but some C code (written to work also
@@ -1333,6 +1333,13 @@
  ## POSIX times.
  R_SYS_POSIX_LEAPSECONDS

+dnl some Solaris systems don't have a tm_zone member in struct tm.
+AC_CHECK_MEMBERS([struct tm.tm_zone],,,[
+#if defined(HAVE_TIME_H)
+#include <time.h>
+#endif
+])
+
  ## R profiling.
  if test "${want_R_profiling}" = yes; then
    AC_CHECK_FUNCS(setitimer,

The configure patch makes sure we know that struct tm.tm_zone exists 
and the other patch makes sure it's reset before calling strftime. Any 
variation hereof would help, too ;)

> Changing the TZ environment variable, from the default of "" to 
> "US/Pacific" does not help.

Doing so has no effect for you, because the time zone is correct as you 
demonstrated yourself in the above output.

Cheers,
Simon



More information about the R-SIG-Mac mailing list