From jeff.a.ryan at gmail.com  Fri Feb 27 19:06:18 2009
From: jeff.a.ryan at gmail.com (Jeff Ryan)
Date: Fri, 27 Feb 2009 12:06:18 -0600
Subject: [Rd] POSIXlt, POSIXct, strptime, GMT and 1969-12-31 23:59:59
Message-ID: <e8e755250902271006k11d9e278g2a96758645da9029@mail.gmail.com>

R-devel:

Some very inconsistent behavior, that I can't seem to find documented.

Sys.setenv(TZ="GMT")

str(unclass(strptime("1969-12-31 23:59:59","%Y-%m-%d %H:%M:%S")))
List of 9
 $ sec  : num 59
 $ min  : int 59
 $ hour : int 23
 $ mday : int 31
 $ mon  : int 11
 $ year : int 69
 $ wday : int 3
 $ yday : int 364
 $ isdst: int 0
 - attr(*, "tzone")= chr "GMT"

# setting to 59 seconds now reports 0
str(unclass(as.POSIXlt("1969-12-31 23:59:59")))
List of 9
 $ sec  : num 0
 $ min  : int 59
 $ hour : int 23
 $ mday : int 31
 $ mon  : int 11
 $ year : int 69
 $ wday : int 3
 $ yday : int 364
 $ isdst: int 0
 - attr(*, "tzone")= chr "GMT"
>

Setting the secs in the string to 58 returns a correct structure:
str(unclass(as.POSIXlt("1969-12-31 23:59:58")))
List of 9
 $ sec  : num 58
 $ min  : int 59
 $ hour : int 23
 $ mday : int 31
 $ mon  : int 11
 $ year : int 69
 $ wday : int 3
 $ yday : int 364
 $ isdst: int 0
 - attr(*, "tzone")= chr "GMT"

Some additional strangeness occurs once as.POSIXct is called:

str(as.POSIXct(as.POSIXlt("1969-12-31 23:59:58")))
 POSIXct[1:1], format: "1969-12-31 23:59:58"

# this incorrectly ignores the secs
str(as.POSIXct(as.POSIXlt("1969-12-31 23:59:59")))
 POSIXct[1:1], format: "1969-12-31 23:59:00"

# this should be -1, if I am not mistaken
str(as.POSIXct(strptime("1969-12-31 23:59:59","%Y-%m-%d %H:%M:%S")))
 POSIXct[1:1], format: NA

According to ?strptime NA should be returned if the time doesn't
exist.  As far as I can tell, 1969-12-31 23:59:59 does exists.

Using a simple C program (source follows this message):

[veblen:~/Rforge/xts] jryan% ./a.out
Date as tm struct (POSIXlt):1969-12-31 23:59:59
   sec: 59
   min: 59
  hour: 23
  mday: 31
   mon: 11
  year: 69
  wday: 3
  yday: 364
seconds since the Epoch: -1

Which gives the -1. This is all run on a Intel Mac, though has been
tested on FreeBSD and Ubuntu as well with the same outcome.  It does
seem to work fine on Windows though.  I think the workaround for
Windows is what is causing the failure elsewhere.

As far as I can see, the code that is causing this is do_asPOSIXct in
datetime.c:

 695     if(!R_FINITE(secs) || tm.tm_min == NA_INTEGER ||
 696        tm.tm_hour == NA_INTEGER || tm.tm_mday == NA_INTEGER ||
 697        tm.tm_mon == NA_INTEGER || tm.tm_year == NA_INTEGER)
 698         REAL(ans)[i] = NA_REAL;
 699     else {
 700         errno = 0;
 701         tmp = mktime0(&tm, 1 - isgmt);
 702 #ifdef MKTIME_SETS_ERRNO
 703         REAL(ans)[i] = errno ? NA_REAL : tmp + (secs - fsecs);
 704 #else
 705         REAL(ans)[i] = (tmp == (double)(-1)) ?
 706         NA_REAL : tmp + (secs - fsecs);
 707 #endif
 708     }

I haven't been able to look further into this logic, but the test for
-1 strikes me as where this is happening.

Thank you for any insight you can provide.

Jeff

> sessionInfo()
R version 2.9.0 Under development (unstable) (2009-02-27 r48020)
i386-apple-darwin8.11.1

locale:
C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base


######### C PROGRAM #########

#include <time.h>
#include <stdio.h>
/*
   code modified from:

   http://www.opengroup.org/onlinepubs/009695399/functions/strptime.html
   by Jeff Ryan
*/

struct tm tm;
time_t t;


int main()
{
char DATE[] = "1969-12-31 23:59:59";
printf("Date as tm struct (POSIXlt):%s\n", DATE);

strptime(DATE, "%Y-%m-%d %H:%M:%S", &tm);

tm.tm_isdst = -1;      /* Not set by strptime(); tells mktime()
                          to determine whether daylight saving time
                          is in effect */
t = mktime(&tm);
printf(
       "   sec: %d\n"
       "   min: %d\n"
       "  hour: %d\n"
       "  mday: %d\n"
       "   mon: %d\n"
       "  year: %d\n"
       "  wday: %d\n"
       "  yday: %d\n",
       tm.tm_sec,
       tm.tm_min,
       tm.tm_hour,
       tm.tm_mday,
       tm.tm_mon,
       tm.tm_year,
       tm.tm_wday,
       tm.tm_yday);

printf("seconds since the Epoch: %d\n", t);
return 0;
}


-- 
Jeffrey Ryan
jeffrey.ryan at insightalgo.com

ia: insight algorithmics
www.insightalgo.com



[Rd] POSIXlt, POSIXct, strptime, GMT and 1969-12-31 23:59:59
Jeff Ryan