[Rd] POSIXlt, POSIXct, strptime, GMT and 1969-12-31 23:59:59
Jeff Ryan
jeff.a.ryan at gmail.com
Fri Feb 27 19:06:18 CET 2009
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
More information about the R-devel
mailing list