The R Project SVN R

Rev

Rev 62622 | Rev 64239 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
10916 ripley 1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
59035 ripley 3
 *  Copyright (C) 2000-2012  The R Core Team.
10916 ripley 4
 *
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
42307 ripley 16
 *  along with this program; if not, a copy is available at
17
 *  http://www.r-project.org/Licenses/
10916 ripley 18
 *
19
 *
20
 *      Interfaces to POSIX date and time functions.
21
 */
22
 
23
/*
24
    These use POSIX functions that are not available on all platforms,
55894 ripley 25
    and where they are they may be partially or incorrectly
26
    implemented.  A number of lightweight alternatives are supplied,
27
    but generally timezone support is only available if the OS
57499 ripley 28
    supplies it (or as on Windows, we replace it).  However, as these
29
    are now also mandated by C99, they are almost universally
30
    available, albeit with more room for implementation variations.
10916 ripley 31
 
55894 ripley 32
    A particular problem is the setting of the timezone TZ on
33
    Unix/Linux.  POSIX appears to require it, yet older Linux systems
34
    do not set it and do not give the correct results/crash strftime
35
    if it is not set (or even if it is: see the workaround below).  We
57499 ripley 36
    use unsetenv() to work around this: that is a BSD (and POSIX 2001)
37
    construct but seems to be available on the affected platforms.
55894 ripley 38
 
39
    Notes on various time functions:
57499 ripley 40
    ===============================
55894 ripley 41
 
42
    The current (2008) POSIX recommendation to find the calendar time
43
    is to call clock_gettime(), defined in <time.h>.  This may also be
44
    used to find time since some unspecified starting point
45
    (e.g. machine reboot), but is not currently so used in R.  It
46
    returns in second and nanoseconds, although not necessarily to
47
    more than clock-tick accuracy.
48
 
58049 ripley 49
    C11 adds 'struct timespec' to <time.h>.  And timespec_get() can get
50
    the current time or interval after a base time.
51
 
55894 ripley 52
    The previous POSIX recommendation was gettimeofday(), defined in
53
    <sys/time.h>.  This returns in seconds and microseconds (with
54
    unspecified granularity).
55
 
56
    Many systems (including AIX, FreeBSD, Linux, Solaris) have
57
    clock_gettime().  Mac OS X and Cygwin have gettimeofday().
58
 
59
    Function time() is C99 and defined in <time.h>.  C99 does not
60
    mandate the units, but POSIX does (as the number of seconds since
61
    the epoch: although not mandated, time_t seems always to be an
62
    integer type).
63
 
64
    Function clock() is C99 and defined in <time.h>.  It measures CPU
65
    time at CLOCKS_PER_SEC: there is a small danger of integer
66
    overflow.
67
 
68
    Function times() is POSIX and defined in <sys/times.h>.  It
69
    returns the elapsed time in clock ticks, plus CPU times in a
70
    struct tms* argument (also in clock ticks).
71
 
72
    More precise information on CPU times may be available from the
73
    POSIX function getrusage() defined in <sys/resource.h>.  This
74
    returns the same time structure as gettimeofday() and on some
75
    systems offers millisecond resolution.
57499 ripley 76
    It is available on Cygwin, FreeBSD, Mac OS X, Linux and Solaris.
77
 
78
    currentTime() (in this file) uses
57572 ripley 79
    clock_gettime(): AIX, FreeBSD, Linux, Solaris
80
    gettimeofday():  Mac OS X, Windows, Cygwin
57499 ripley 81
    time() (as ultimate fallback, AFAIK unused).
82
 
83
    proc.time() uses currentTime() for elapsed time,
84
    and getrusage, then times for CPU times on a Unix-alike,
85
    GetProcessTimes on Windows.
86
 
87
    devPS.c uses time() and localtime() for timestamps.
57503 ripley 88
 
89
    do_date (platform.c) uses ctime.
10916 ripley 90
 */
91
 
10543 ripley 92
#ifdef HAVE_CONFIG_H
10819 hornik 93
# include <config.h>
10543 ripley 94
#endif
10819 hornik 95
 
43810 ripley 96
/* needed on Windows to avoid redefinition of tzname as _tzname */
97
#define _NO_OLDNAMES
36622 ripley 98
#include <time.h>
43810 ripley 99
#undef _NO_OLDNAMES
100
 
43843 ripley 101
#include <errno.h>
102
 
43828 ripley 103
#ifdef Win32
104
#define gmtime R_gmtime
105
#define localtime R_localtime
106
#define mktime R_mktime
107
extern struct tm*  gmtime (const time_t*);
108
extern struct tm*  localtime (const time_t*);
109
extern time_t mktime (struct tm*);
110
#endif
111
 
40392 ripley 112
#include <stdlib.h> /* for setenv or putenv */
36496 ripley 113
#include <Defn.h>
60667 ripley 114
#include <Internal.h>
10543 ripley 115
 
43825 ripley 116
/* The glibc in RH8.0 was broken and assumed that dates before
117
   1970-01-01 do not exist.  So does Windows, but its code was replaced
118
   in R 2.7.0.  As from 1.6.2, test the actual mktime code and cache
119
   the result on glibc >= 2.2. (It seems this started between 2.2.5
120
   and 2.3, and RH8.0 had an unreleased version in that gap.)
35955 ripley 121
 
122
   Sometime in late 2004 this was reverted in glibc.
22614 ripley 123
*/
22594 ripley 124
 
125
static Rboolean have_broken_mktime(void)
126
{
43825 ripley 127
#if defined(_AIX)
22594 ripley 128
    return TRUE;
129
#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 2
22614 ripley 130
    static int test_result = -1;
28584 ripley 131
 
22614 ripley 132
    if (test_result == -1) {
133
	struct tm t;
134
	time_t res;
135
	t.tm_sec = t.tm_min = t.tm_hour = 0;
136
	t.tm_mday = t.tm_mon = 1;
137
	t.tm_year = 68;
138
	t.tm_isdst = -1;
139
	res = mktime(&t);
140
	test_result = (res == (time_t)-1);
141
    }
142
    return test_result > 0;
22594 ripley 143
#else
144
    return FALSE;
145
#endif
146
 
147
 
148
}
149
 
10543 ripley 150
/* Substitute based on glibc code. */
37398 ripley 151
#include "Rstrptime.h"
10543 ripley 152
 
153
static const int days_in_month[12] =
154
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
155
 
156
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
157
#define days_in_year(year) (isleap(year) ? 366 : 365)
158
 
15332 hornik 159
#ifndef HAVE_POSIX_LEAPSECONDS
59689 ripley 160
/* There have been 25 leapseconds: see .leap.seconds in R
37077 ripley 161
 */
59689 ripley 162
static int n_leapseconds = 25;
10543 ripley 163
static const time_t leapseconds[] =
164
{  78796800, 94694400,126230400,157766400,189302400,220924800,252460800,
37077 ripley 165
  283996800,315532800,362793600,394329600,425865600,489024000,567993600,
10543 ripley 166
  631152000,662688000,709948800,741484800,773020800,820454400,867715200,
59689 ripley 167
   915148800,1136073600,1230768000,1341100800};
10543 ripley 168
#endif
169
 
170
/*
10819 hornik 171
  Adjust a struct tm to be a valid date-time.
172
  Return 0 if valid, -1 if invalid and uncorrectable, or a positive
173
  integer approximating the number of corrections needed.
174
  */
10543 ripley 175
static int validate_tm (struct tm *tm)
176
{
177
    int tmp, res = 0;
178
 
179
    if (tm->tm_sec < 0 || tm->tm_sec > 60) { /* 61 POSIX, 60 draft ISO C */
180
	res++;
181
	tmp = tm->tm_sec/60;
182
	tm->tm_sec -= 60 * tmp; tm->tm_min += tmp;
183
	if(tm->tm_sec < 0) {tm->tm_sec += 60; tm->tm_min--;}
184
    }
185
 
186
    if (tm->tm_min < 0 || tm->tm_min > 59) {
187
	res++;
188
	tmp = tm->tm_min/60;
189
	tm->tm_min -= 60 * tmp; tm->tm_hour += tmp;
190
	if(tm->tm_min < 0) {tm->tm_min += 60; tm->tm_hour--;}
191
    }
192
 
55940 ripley 193
    if(tm->tm_hour == 24 && tm->tm_min == 0 && tm->tm_sec == 0) {
194
	tm->tm_hour = 0; tm->tm_mday++;
195
	if(tm->tm_mon >= 0 && tm->tm_mon <= 11) {
196
	    if(tm->tm_mday > days_in_month[tm->tm_mon] +
197
	       ((tm->tm_mon==1 && isleap(1900+tm->tm_year) ? 1 : 0))) {
198
		   tm->tm_mon++; tm->tm_mday = 1;
199
		   if(tm->tm_mon == 12) {
200
		       tm->tm_year++; tm->tm_mon = 0;
201
		   }
202
	       }
203
	}
204
    }
10543 ripley 205
    if (tm->tm_hour < 0 || tm->tm_hour > 23) {
55940 ripley 206
	res++;
10543 ripley 207
	tmp = tm->tm_hour/24;
208
	tm->tm_hour -= 24 * tmp; tm->tm_mday += tmp;
209
	if(tm->tm_hour < 0) {tm->tm_hour += 24; tm->tm_mday--;}
210
    }
211
 
212
    /* defer fixing mday until we know the year */
213
    if (tm->tm_mon < 0 || tm->tm_mon > 11) {
214
	res++;
215
	tmp = tm->tm_mon/12;
216
	tm->tm_mon -= 12 * tmp; tm->tm_year += tmp;
217
	if(tm->tm_mon < 0) {tm->tm_mon += 12; tm->tm_year--;}
218
    }
219
 
27909 ripley 220
    /* A limit on the loops of about 3000x round */
221
    if(tm->tm_mday < -1000000 || tm->tm_mday > 1000000) return -1;
10543 ripley 222
 
27909 ripley 223
    if(abs(tm->tm_mday) > 366) {
224
	res++;
225
	/* first spin back until January */
226
	while(tm->tm_mon > 0) {
227
	    --tm->tm_mon;
228
	    tm->tm_mday += days_in_month[tm->tm_mon] +
229
	    ((tm->tm_mon==1 && isleap(1900+tm->tm_year))? 1 : 0);
230
	}
231
	/* then spin on/back by years */
232
	while(tm->tm_mday < 1) {
233
	    --tm->tm_year;
234
	    tm->tm_mday += 365 + (isleap(1900+tm->tm_year)? 1 : 0);
235
	}
236
	while(tm->tm_mday >
237
	      (tmp = 365 + (isleap(1900+tm->tm_year)? 1 : 0))) {
238
	    tm->tm_mday -= tmp; tm->tm_year++;
239
	}
240
    }
10543 ripley 241
 
10872 ripley 242
    while(tm->tm_mday < 1) {
10543 ripley 243
	res++;
244
	if(--tm->tm_mon < 0) {tm->tm_mon += 12; tm->tm_year--;}
245
	tm->tm_mday += days_in_month[tm->tm_mon] +
246
	    ((tm->tm_mon==1 && isleap(1900+tm->tm_year))? 1 : 0);
247
    }
248
 
249
    while(tm->tm_mday >
250
	  (tmp = days_in_month[tm->tm_mon] +
251
	   ((tm->tm_mon==1 && isleap(1900+tm->tm_year))? 1 : 0))) {
252
	res++;
253
	if(++tm->tm_mon > 11) {tm->tm_mon -= 12; tm->tm_year++;}
254
	tm->tm_mday -= tmp;
255
    }
256
    return res;
257
}
258
 
259
 
260
/* Substitute for mktime -- no checking, always in GMT */
261
static double mktime00 (struct tm *tm)
262
{
35334 ripley 263
    int day = 0;
10543 ripley 264
    int i, year, year0;
59102 ripley 265
    double excess = 0.0;
45446 ripley 266
 
10543 ripley 267
    day = tm->tm_mday - 1;
268
    year0 = 1900 + tm->tm_year;
12778 pd 269
    /* safety check for unbounded loops */
35585 ripley 270
    if (year0 > 3000) {
271
	excess = (int)(year0/2000) - 1;
59202 ripley 272
	year0 -= (int)(excess * 2000);
35585 ripley 273
    } else if (year0 < 0) {
274
	excess = -1 - (int)(-year0/2000);
59202 ripley 275
	year0 -= (int)(excess * 2000);
35585 ripley 276
    }
12778 pd 277
 
10543 ripley 278
    for(i = 0; i < tm->tm_mon; i++) day += days_in_month[i];
279
    if (tm->tm_mon > 1 && isleap(year0)) day++;
280
    tm->tm_yday = day;
281
 
282
    if (year0 > 1970) {
283
	for (year = 1970; year < year0; year++)
284
	    day += days_in_year(year);
285
    } else if (year0 < 1970) {
286
	for (year = 1969; year >= year0; year--)
287
	    day -= days_in_year(year);
288
    }
289
 
290
    /* weekday: Epoch day was a Thursday */
291
    if ((tm->tm_wday = (day + 4) % 7) < 0) tm->tm_wday += 7;
292
 
293
    return tm->tm_sec + (tm->tm_min * 60) + (tm->tm_hour * 3600)
59102 ripley 294
	+ (day + excess * 730485) * 86400.0;
10543 ripley 295
}
296
 
297
static double guess_offset (struct tm *tm)
298
{
299
    double offset, offset1, offset2;
40947 ripley 300
    int i, wday, year, oldmonth, oldisdst, oldmday;
301
    struct tm oldtm;
10543 ripley 302
    /*
35955 ripley 303
       Adjust as best we can for timezones: if isdst is unknown, use
304
       the smaller offset at same day in Jan or July of a valid year.
305
       We don't know the timezone rules, but if we choose a year with
306
       July 1 on the same day of the week we will likely get guess
43825 ripley 307
       right (since they are usually on Sunday mornings not in Jan/Feb).
308
 
309
       Update for 2.7.0: no one had DST before 1916, so just use the offset
310
       in 1902, if available.
10543 ripley 311
    */
40947 ripley 312
 
313
    memcpy(&oldtm, tm, sizeof(struct tm));
43825 ripley 314
    if(!have_broken_mktime() && tm->tm_year < 2) { /* no DST */
315
	tm->tm_year = 2;
316
	mktime(tm);
317
	offset1 = (double) mktime(tm) - mktime00(tm);
318
	memcpy(tm, &oldtm, sizeof(struct tm));
319
	tm->tm_isdst = 0;
320
	return offset1;
321
    }
10543 ripley 322
    oldmonth = tm->tm_mon;
35955 ripley 323
    oldmday = tm->tm_mday;
43825 ripley 324
    /* We know there was no DST prior to 1916 */
325
    oldisdst = (tm->tm_year < 16) ? 0 : tm->tm_isdst;
35955 ripley 326
 
327
    /* so now look for a suitable year */
328
    tm->tm_mon = 6;
329
    tm->tm_mday = 1;
330
    tm->tm_isdst = -1;
331
    mktime00(tm);  /* to get wday valid */
332
    wday = tm->tm_wday;
43825 ripley 333
    if (oldtm.tm_year > 137) { /* in the unknown future */
334
	for(i = 130; i < 137; i++) { /* These cover all the possibilities */
335
	    tm->tm_year = i;
336
	    mktime(tm);
337
	    if(tm->tm_wday == wday) break;
338
	}
339
    } else { /* a benighted OS with date before 1970 */
45446 ripley 340
	/* We could not use 1970 because of the Windows bug with
43825 ripley 341
	   1970-01-01 east of GMT. */
342
	for(i = 71; i < 82; i++) { /* These cover all the possibilities */
343
	    tm->tm_year = i;
344
	    mktime(tm);
345
	    if(tm->tm_wday == wday) break;
346
	}
35955 ripley 347
    }
348
    year = i;
349
 
350
    /* Now look up offset in January */
351
    tm->tm_mday = oldmday;
10543 ripley 352
    tm->tm_mon = 0;
35955 ripley 353
    tm->tm_year = year;
12256 pd 354
    tm->tm_isdst = -1;
10543 ripley 355
    offset1 = (double) mktime(tm) - mktime00(tm);
35955 ripley 356
    /* and in July */
357
    tm->tm_year = year;
10543 ripley 358
    tm->tm_mon = 6;
12256 pd 359
    tm->tm_isdst = -1;
10543 ripley 360
    offset2 = (double) mktime(tm) - mktime00(tm);
40947 ripley 361
    if(oldisdst > 0) {
12256 pd 362
	offset = (offset1 > offset2) ? offset2 : offset1;
363
    } else {
10543 ripley 364
	offset = (offset1 > offset2) ? offset1 : offset2;
365
    }
12256 pd 366
    /* now try to guess dst if unknown */
367
    tm->tm_mon = oldmonth;
368
    tm->tm_isdst = -1;
40947 ripley 369
    if(oldisdst < 0) {
12256 pd 370
	offset1 = (double) mktime(tm) - mktime00(tm);
40947 ripley 371
	oldisdst = (offset1 < offset) ? 1:0;
372
	if(oldisdst) offset = offset1;
12256 pd 373
    }
40947 ripley 374
    /* restore all as mktime might alter it */
375
    memcpy(tm, &oldtm, sizeof(struct tm));
376
    /* and then set isdst */
377
    tm->tm_isdst = oldisdst;
10543 ripley 378
    return offset;
379
}
380
 
381
/* Interface to mktime or mktime00 */
12778 pd 382
static double mktime0 (struct tm *tm, const int local)
10543 ripley 383
{
384
    double res;
28584 ripley 385
    Rboolean OK;
15332 hornik 386
#ifndef HAVE_POSIX_LEAPSECONDS
10543 ripley 387
    int i;
388
#endif
389
 
43843 ripley 390
    if(validate_tm(tm) < 0) {
391
#ifdef EOVERFLOW
392
	errno = EOVERFLOW;
393
#else
394
	errno = 79;
395
#endif
396
	return (double)(-1);
397
    }
12778 pd 398
    if(!local) return mktime00(tm);
10543 ripley 399
 
28584 ripley 400
    OK = tm->tm_year < 138 && tm->tm_year >= (have_broken_mktime() ? 70 : 02);
401
    if(OK) {
402
	res = (double) mktime(tm);
35585 ripley 403
	if (res == (double)-1) return res;
15332 hornik 404
#ifndef HAVE_POSIX_LEAPSECONDS
45446 ripley 405
	for(i = 0; i < n_leapseconds; i++)
406
	    if(res > leapseconds[i]) res -= 1.0;
10543 ripley 407
#endif
45446 ripley 408
	return res;
10543 ripley 409
/* watch the side effect here: both calls alter their arg */
410
    } else return guess_offset(tm) + mktime00(tm);
411
}
412
 
413
/* Interface for localtime or gmtime or internal substitute */
19912 duncan 414
static struct tm * localtime0(const double *tp, const int local, struct tm *ltm)
10543 ripley 415
{
416
    double d = *tp;
35952 ripley 417
    int y, tmp, mon, left, diff, diff2;
19912 duncan 418
    struct tm *res= ltm;
43840 ripley 419
    time_t t;
10543 ripley 420
 
22594 ripley 421
    if(d < 2147483647.0 && d > (have_broken_mktime() ? 0. : -2147483647.0)) {
10543 ripley 422
	t = (time_t) d;
52866 urbaneks 423
	/* if d is negative and non-integer then t will be off by one day
424
	   since we really need floor(). But floor() is slow, so we just
425
	   fix t instead as needed. */
426
	if (d < 0.0 && (double) t != d) t--;
15332 hornik 427
#ifndef HAVE_POSIX_LEAPSECONDS
45446 ripley 428
	for(y = 0; y < n_leapseconds; y++) if(t > leapseconds[y] + y - 1) t++;
10543 ripley 429
#endif
430
	return local ? localtime(&t) : gmtime(&t);
431
    }
43840 ripley 432
 
62314 ripley 433
    int day = (int) floor(d/86400.0);
62196 ripley 434
    left = (int) (d - day * 86400.0 + 1e-6); // allow for fractional secs
10543 ripley 435
 
436
    /* hour, min, and sec */
437
    res->tm_hour = left / 3600;
438
    left %= 3600;
439
    res->tm_min = left / 60;
440
    res->tm_sec = left % 60;
441
 
442
    /* weekday: 1970-01-01 was a Thursday */
443
    if ((res->tm_wday = ((4 + day) % 7)) < 0) res->tm_wday += 7;
444
 
445
    /* year & day within year */
446
    y = 1970;
447
    if (day >= 0)
448
	for ( ; day >= (tmp = days_in_year(y)); day -= tmp, y++);
449
    else
450
	for ( ; day < 0; --y, day += days_in_year(y) );
451
 
452
    y = res->tm_year = y - 1900;
453
    res->tm_yday = day;
454
 
455
    /* month within year */
456
    for (mon = 0;
27157 ripley 457
	 day >= (tmp = (days_in_month[mon]) + ((mon==1 && isleap(y+1900))?1:0));
10543 ripley 458
	 day -= tmp, mon++);
459
    res->tm_mon = mon;
460
    res->tm_mday = day + 1;
461
 
462
    if(local) {
35952 ripley 463
	int shift;
10543 ripley 464
	/*  daylight saving time is unknown */
465
	res->tm_isdst = -1;
466
 
467
	/* Try to fix up timezone differences */
59170 ripley 468
	diff = (int)(guess_offset(res)/60);
35952 ripley 469
	shift = res->tm_min + 60*res->tm_hour;
470
	res->tm_min -= diff;
10543 ripley 471
	validate_tm(res);
35952 ripley 472
	res->tm_isdst = -1;
473
	/* now this might be a different day */
474
	if(shift - diff < 0) res->tm_yday--;
45446 ripley 475
	if(shift - diff > 24) res->tm_yday++;
59170 ripley 476
	diff2 = (int)(guess_offset(res)/60);
35952 ripley 477
	if(diff2 != diff) {
478
	    res->tm_min += (diff - diff2);
479
	    validate_tm(res);
480
	}
10543 ripley 481
	return res;
482
    } else {
483
	res->tm_isdst = 0; /* no dst in GMT */
484
	return res;
485
    }
486
}
487
 
488
 
58050 ripley 489
/* clock_gettime, timespec_get time are in <time.h>, already included */
36225 ripley 490
#ifdef HAVE_SYS_TIME_H
55804 ripley 491
/* gettimeoday, including on Windows */
36225 ripley 492
# include <sys/time.h>
493
#endif
10543 ripley 494
 
55800 ripley 495
double currentTime(void)
10543 ripley 496
{
55800 ripley 497
    double ans = NA_REAL;
498
 
58050 ripley 499
#ifdef HAVE_TIMESPEC_GET
55800 ripley 500
    struct timespec tp;
58050 ripley 501
    int res = timespec_get(&tp, TIME_UTC);
502
    if(res != 0)
503
	ans = (double) tp.tv_sec + 1e-9 * (double) tp.tv_nsec;
504
#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
505
    struct timespec tp;
55803 ripley 506
    int res = clock_gettime(CLOCK_REALTIME, &tp);
507
    if(res == 0)
508
	ans = (double) tp.tv_sec + 1e-9 * (double) tp.tv_nsec;
55800 ripley 509
 
55804 ripley 510
#elif defined(HAVE_GETTIMEOFDAY)
57499 ripley 511
    /* Mac OS X, mingw.org */
36225 ripley 512
    struct timeval tv;
513
    int res = gettimeofday(&tv, NULL);
55803 ripley 514
    if(res == 0)
515
	ans = (double) tv.tv_sec + 1e-6 * (double) tv.tv_usec;
55800 ripley 516
 
36225 ripley 517
#else
55894 ripley 518
    /* No known current OSes */
36225 ripley 519
    time_t res = time(NULL);
58417 maechler 520
    if(res != (time_t)(-1)) /* -1 must be an error as the real value -1
55894 ripley 521
			       was ca 1969 */
55804 ripley 522
	ans = (double) res;
36227 ripley 523
#endif
55800 ripley 524
 
55803 ripley 525
#ifndef HAVE_POSIX_LEAPSECONDS
526
    /* No known current OSes */
55807 ripley 527
    /* Disallowed by POSIX (1988-):
528
       http://www.mail-archive.com/leapsecs@rom.usno.navy.mil/msg00109.html
529
       http://en.wikipedia.org/wiki/Unix_time
530
    */
55803 ripley 531
    if (!ISNAN(ans)) {
532
	ans -= n_leapseconds;
533
    }
534
#endif
10543 ripley 535
    return ans;
55800 ripley 536
}
537
 
538
SEXP attribute_hidden do_systime(SEXP call, SEXP op, SEXP args, SEXP env)
539
{
540
    return ScalarReal(currentTime());
541
}
542
 
56607 ripley 543
#ifdef HAVE_UNISTD_H
544
#include <unistd.h> /* for getpid */
545
#endif
546
 
55805 ripley 547
/* For RNG.c, main.c, mkdtemp.c */
55800 ripley 548
attribute_hidden
549
unsigned int TimeToSeed(void)
550
{
56607 ripley 551
    unsigned int seed, pid = getpid();
55800 ripley 552
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
553
    {
554
	struct timespec tp;
55804 ripley 555
	clock_gettime(CLOCK_REALTIME, &tp);
59170 ripley 556
	seed = (unsigned int)(((uint_least64_t) tp.tv_nsec << 16) ^ tp.tv_sec);
55800 ripley 557
    }
558
#elif defined(HAVE_GETTIMEOFDAY)
559
    {
560
	struct timeval tv;
561
	gettimeofday (&tv, NULL);
59170 ripley 562
	seed = (unsigned int)(((uint_least64_t) tv.tv_usec << 16) ^ tv.tv_sec);
55800 ripley 563
    }
55804 ripley 564
#else
565
    /* C89, so must work */
55800 ripley 566
    seed = (Int32) time(NULL);
567
#endif
56607 ripley 568
    seed ^= (pid <<16);
55800 ripley 569
    return seed;
10543 ripley 570
}
571
 
12778 pd 572
 
51426 ripley 573
#ifdef Win32
43810 ripley 574
extern void tzset(void);
51426 ripley 575
/* tzname is in the headers as an import on MinGW-w64 */
50936 ripley 576
#define tzname Rtzname
577
extern char *Rtzname[2];
42600 ripley 578
#elif defined(__CYGWIN__)
579
extern __declspec(dllimport) char *tzname[2];
43810 ripley 580
#else
10543 ripley 581
extern char *tzname[2];
582
#endif
583
 
41807 rgentlem 584
static int set_tz(const char *tz, char *oldtz)
12778 pd 585
{
586
    char *p = NULL;
587
    int settz = 0;
16537 ripley 588
 
12778 pd 589
    strcpy(oldtz, "");
590
    p = getenv("TZ");
59629 ripley 591
    if(p) {
592
	if (strlen(p) > 1000)
593
	    error("time zone specification is too long");
594
	strcpy(oldtz, p);
595
    }
40391 ripley 596
#ifdef HAVE_SETENV
40392 ripley 597
    if(setenv("TZ", tz, 1)) warning(_("problem with setting timezone"));
12778 pd 598
    settz = 1;
40391 ripley 599
#elif defined(HAVE_PUTENV)
600
    {
59629 ripley 601
	static char buff[1010];
59631 murdoch 602
	if (strlen(tz) > 1000)
59629 ripley 603
	    error("time zone specification is too long");
40391 ripley 604
	strcpy(buff, "TZ="); strcat(buff, tz);
40392 ripley 605
	if(putenv(buff)) warning(_("problem with setting timezone"));
40391 ripley 606
    }
607
    settz = 1;
12778 pd 608
#else
32861 ripley 609
    warning(_("cannot set timezones on this system"));
12778 pd 610
#endif
611
    tzset();
612
    return settz;
613
}
614
 
615
static void reset_tz(char *tz)
616
{
617
    if(strlen(tz)) {
40391 ripley 618
#ifdef HAVE_SETENV
40392 ripley 619
	if(setenv("TZ", tz, 1)) warning(_("problem with setting timezone"));
40391 ripley 620
#elif defined(HAVE_PUTENV)
621
	{
622
	    static char buff[200];
623
	    strcpy(buff, "TZ="); strcat(buff, tz);
40392 ripley 624
	    if(putenv(buff)) warning(_("problem with setting timezone"));
40391 ripley 625
	}
12778 pd 626
#endif
627
    } else {
628
#ifdef HAVE_UNSETENV
40404 ripley 629
	unsetenv("TZ"); /* FreeBSD variants do not return a value */
40391 ripley 630
#elif defined(HAVE_PUTENV_UNSET)
40392 ripley 631
	if(putenv("TZ")) warning(_("problem with unsetting timezone"));
40391 ripley 632
#elif defined(HAVE_PUTENV_UNSET2)
40392 ripley 633
	if(putenv("TZ=")) warning(_("problem with unsetting timezone"));
12778 pd 634
#endif
635
    }
636
    tzset();
637
}
638
 
639
 
19912 duncan 640
static const char ltnames [][6] =
10543 ripley 641
{ "sec", "min", "hour", "mday", "mon", "year", "wday", "yday", "isdst" };
642
 
643
 
60241 ripley 644
static void 
645
makelt(struct tm *tm, SEXP ans, R_xlen_t i, int valid, double frac_secs)
10543 ripley 646
{
647
    if(valid) {
37334 ripley 648
	REAL(VECTOR_ELT(ans, 0))[i] = tm->tm_sec + frac_secs;
10543 ripley 649
	INTEGER(VECTOR_ELT(ans, 1))[i] = tm->tm_min;
650
	INTEGER(VECTOR_ELT(ans, 2))[i] = tm->tm_hour;
651
	INTEGER(VECTOR_ELT(ans, 3))[i] = tm->tm_mday;
652
	INTEGER(VECTOR_ELT(ans, 4))[i] = tm->tm_mon;
653
	INTEGER(VECTOR_ELT(ans, 5))[i] = tm->tm_year;
654
	INTEGER(VECTOR_ELT(ans, 6))[i] = tm->tm_wday;
655
	INTEGER(VECTOR_ELT(ans, 7))[i] = tm->tm_yday;
656
	INTEGER(VECTOR_ELT(ans, 8))[i] = tm->tm_isdst;
657
    } else {
37334 ripley 658
	REAL(VECTOR_ELT(ans, 0))[i] = NA_REAL;
60241 ripley 659
	for(int j = 1; j < 8; j++)
10543 ripley 660
	    INTEGER(VECTOR_ELT(ans, j))[i] = NA_INTEGER;
661
	INTEGER(VECTOR_ELT(ans, 8))[i] = -1;
662
    }
663
}
664
 
665
 
36990 ripley 666
SEXP attribute_hidden do_asPOSIXlt(SEXP call, SEXP op, SEXP args, SEXP env)
10543 ripley 667
{
39866 duncan 668
    SEXP stz, x, ans, ansnames, klass, tzone;
60241 ripley 669
    int isgmt = 0, valid, settz = 0;
59629 ripley 670
    char oldtz[1001] = "";
41807 rgentlem 671
    const char *tz = NULL;
10543 ripley 672
 
673
    checkArity(op, args);
674
    PROTECT(x = coerceVector(CAR(args), REALSXP));
675
    if(!isString((stz = CADR(args))) || LENGTH(stz) != 1)
35265 ripley 676
	error(_("invalid '%s' value"), "tz");
10543 ripley 677
    tz = CHAR(STRING_ELT(stz, 0));
34315 ripley 678
    if(strlen(tz) == 0) {
679
	/* do a direct look up here as this does not otherwise
680
	   work on Windows */
681
	char *p = getenv("TZ");
52570 murdoch 682
	if(p) {
683
	    stz = mkString(p); /* make a copy */
684
	    tz = CHAR(STRING_ELT(stz, 0));
685
	}
34315 ripley 686
    }
52570 murdoch 687
    PROTECT(stz); /* it might be new */
10543 ripley 688
    if(strcmp(tz, "GMT") == 0  || strcmp(tz, "UTC") == 0) isgmt = 1;
12778 pd 689
    if(!isgmt && strlen(tz) > 0) settz = set_tz(tz, oldtz);
10543 ripley 690
 
60241 ripley 691
    R_xlen_t n = XLENGTH(x);
10543 ripley 692
    PROTECT(ans = allocVector(VECSXP, 9));
60241 ripley 693
    for(int i = 0; i < 9; i++)
37334 ripley 694
	SET_VECTOR_ELT(ans, i, allocVector(i > 0 ? INTSXP : REALSXP, n));
10543 ripley 695
 
696
    PROTECT(ansnames = allocVector(STRSXP, 9));
60241 ripley 697
    for(int i = 0; i < 9; i++)
10543 ripley 698
	SET_STRING_ELT(ansnames, i, mkChar(ltnames[i]));
699
 
60241 ripley 700
    for(R_xlen_t i = 0; i < n; i++) {
45446 ripley 701
	struct tm dummy, *ptm = &dummy;
37334 ripley 702
	double d = REAL(x)[i];
703
	if(R_FINITE(d)) {
19912 duncan 704
	    ptm = localtime0(&d, 1 - isgmt, &dummy);
10543 ripley 705
	    /* in theory localtime/gmtime always return a valid
706
	       struct tm pointer, but Windows uses NULL for error
707
	       conditions (like negative times). */
708
	    valid = (ptm != NULL);
709
	} else valid = 0;
37334 ripley 710
	makelt(ptm, ans, i, valid, d - floor(d));
10543 ripley 711
    }
712
    setAttrib(ans, R_NamesSymbol, ansnames);
39866 duncan 713
    PROTECT(klass = allocVector(STRSXP, 2));
51712 ripley 714
    SET_STRING_ELT(klass, 0, mkChar("POSIXlt"));
715
    SET_STRING_ELT(klass, 1, mkChar("POSIXt"));
39866 duncan 716
    classgets(ans, klass);
12778 pd 717
    if (isgmt) {
41894 ripley 718
	PROTECT(tzone = mkString(tz));
12778 pd 719
    } else {
720
	PROTECT(tzone = allocVector(STRSXP, 3));
721
	SET_STRING_ELT(tzone, 0, mkChar(tz));
722
	SET_STRING_ELT(tzone, 1, mkChar(tzname[0]));
723
	SET_STRING_ELT(tzone, 2, mkChar(tzname[1]));
724
    }
10543 ripley 725
    setAttrib(ans, install("tzone"), tzone);
52570 murdoch 726
    UNPROTECT(6);
10543 ripley 727
 
12778 pd 728
    if(settz) reset_tz(oldtz);
10543 ripley 729
    return ans;
730
}
731
 
36990 ripley 732
SEXP attribute_hidden do_asPOSIXct(SEXP call, SEXP op, SEXP args, SEXP env)
10543 ripley 733
{
734
    SEXP stz, x, ans;
60241 ripley 735
    R_xlen_t n = 0, nlen[9];
736
    int isgmt = 0, settz = 0;
41807 rgentlem 737
    char oldtz[20] = "";
738
    const char *tz = NULL;
10543 ripley 739
    struct tm tm;
12778 pd 740
    double tmp;
10543 ripley 741
 
742
    checkArity(op, args);
37334 ripley 743
    PROTECT(x = duplicate(CAR(args))); /* coerced below */
10543 ripley 744
    if(!isVectorList(x) || LENGTH(x) != 9)
35264 ripley 745
	error(_("invalid '%s' argument"), "x");
10543 ripley 746
    if(!isString((stz = CADR(args))) || LENGTH(stz) != 1)
35265 ripley 747
	error(_("invalid '%s' value"), "tz");
10543 ripley 748
 
749
    tz = CHAR(STRING_ELT(stz, 0));
34315 ripley 750
    if(strlen(tz) == 0) {
751
	/* do a direct look up here as this does not otherwise
752
	   work on Windows */
753
	char *p = getenv("TZ");
52570 murdoch 754
	if(p) {
755
	    stz = mkString(p);
756
	    tz = CHAR(STRING_ELT(stz, 0));
757
	}
34315 ripley 758
    }
52570 murdoch 759
    PROTECT(stz); /* it might be new */
10543 ripley 760
    if(strcmp(tz, "GMT") == 0  || strcmp(tz, "UTC") == 0) isgmt = 1;
12778 pd 761
    if(!isgmt && strlen(tz) > 0) settz = set_tz(tz, oldtz);
10543 ripley 762
 
60241 ripley 763
    for(int i = 0; i < 6; i++)
764
	if((nlen[i] = XLENGTH(VECTOR_ELT(x, i))) > n) n = nlen[i];
765
    if((nlen[8] = XLENGTH(VECTOR_ELT(x, 8))) > n) n = nlen[8];
10543 ripley 766
    if(n > 0) {
60241 ripley 767
	for(int i = 0; i < 6; i++)
10543 ripley 768
	    if(nlen[i] == 0)
60844 ripley 769
		error(_("zero-length component in non-empty \"POSIXlt\" structure"));
10543 ripley 770
	if(nlen[8] == 0)
60844 ripley 771
	    error(_("zero-length component in non-empty \"POSIXlt\" structure"));
10543 ripley 772
    }
37334 ripley 773
    /* coerce fields to integer or real */
774
    SET_VECTOR_ELT(x, 0, coerceVector(VECTOR_ELT(x, 0), REALSXP));
60241 ripley 775
    for(int i = 0; i < 6; i++)
37334 ripley 776
	SET_VECTOR_ELT(x, i, coerceVector(VECTOR_ELT(x, i),
777
					  i > 0 ? INTSXP: REALSXP));
10543 ripley 778
    SET_VECTOR_ELT(x, 8, coerceVector(VECTOR_ELT(x, 8), INTSXP));
779
 
780
    PROTECT(ans = allocVector(REALSXP, n));
60241 ripley 781
    for(R_xlen_t i = 0; i < n; i++) {
37334 ripley 782
	double secs = REAL(VECTOR_ELT(x, 0))[i%nlen[0]], fsecs = floor(secs);
59170 ripley 783
	tm.tm_sec   = (int) fsecs;
10543 ripley 784
	tm.tm_min   = INTEGER(VECTOR_ELT(x, 1))[i%nlen[1]];
785
	tm.tm_hour  = INTEGER(VECTOR_ELT(x, 2))[i%nlen[2]];
786
	tm.tm_mday  = INTEGER(VECTOR_ELT(x, 3))[i%nlen[3]];
787
	tm.tm_mon   = INTEGER(VECTOR_ELT(x, 4))[i%nlen[4]];
788
	tm.tm_year  = INTEGER(VECTOR_ELT(x, 5))[i%nlen[5]];
789
	/* mktime ignores tm.tm_wday and tm.tm_yday */
790
	tm.tm_isdst = isgmt ? 0:INTEGER(VECTOR_ELT(x, 8))[i%nlen[8]];
37334 ripley 791
	if(!R_FINITE(secs) || tm.tm_min == NA_INTEGER ||
10543 ripley 792
	   tm.tm_hour == NA_INTEGER || tm.tm_mday == NA_INTEGER ||
793
	   tm.tm_mon == NA_INTEGER || tm.tm_year == NA_INTEGER)
794
	    REAL(ans)[i] = NA_REAL;
12778 pd 795
	else {
43843 ripley 796
	    errno = 0;
12778 pd 797
	    tmp = mktime0(&tm, 1 - isgmt);
43843 ripley 798
#ifdef MKTIME_SETS_ERRNO
799
	    REAL(ans)[i] = errno ? NA_REAL : tmp + (secs - fsecs);
800
#else
62622 pd 801
	    REAL(ans)[i] = ((tmp == (double)(-1))
62623 pd 802
			    /* avoid silly gotcha at epoch minus one sec */
803
			    && (tm.tm_sec == 59)
804
			    && ((tm.tm_sec = 58), (mktime0(&tm, 1 - isgmt) != (double)(-2)))
805
			    ) ?
806
	      NA_REAL : tmp + (secs - fsecs);
43843 ripley 807
#endif
10916 ripley 808
	}
10543 ripley 809
    }
10916 ripley 810
 
12778 pd 811
    if(settz) reset_tz(oldtz);
812
 
52570 murdoch 813
    UNPROTECT(3);
10543 ripley 814
    return ans;
815
}
816
 
36990 ripley 817
SEXP attribute_hidden do_formatPOSIXlt(SEXP call, SEXP op, SEXP args, SEXP env)
10543 ripley 818
{
12256 pd 819
    SEXP x, sformat, ans, tz;
60241 ripley 820
    R_xlen_t i, n = 0, m, N, nlen[9];
821
    int UseTZ, settz = 0;
41807 rgentlem 822
    char buff[300];
52762 ripley 823
    char oldtz[20] = "";
824
    const char *p, *tz1;
10543 ripley 825
    struct tm tm;
826
 
827
    checkArity(op, args);
37334 ripley 828
    PROTECT(x = duplicate(CAR(args))); /* coerced below */
10543 ripley 829
    if(!isVectorList(x) || LENGTH(x) != 9)
35264 ripley 830
	error(_("invalid '%s' argument"), "x");
60241 ripley 831
    if(!isString((sformat = CADR(args))) || XLENGTH(sformat) == 0)
35264 ripley 832
	error(_("invalid '%s' argument"), "format");
60241 ripley 833
    m = XLENGTH(sformat);
12256 pd 834
    UseTZ = asLogical(CADDR(args));
835
    if(UseTZ == NA_LOGICAL)
35264 ripley 836
	error(_("invalid '%s' argument"), "usetz");
12256 pd 837
    tz = getAttrib(x, install("tzone"));
10543 ripley 838
 
52762 ripley 839
    if (!isNull(tz) && strlen(tz1 = CHAR(STRING_ELT(tz, 0)))) {
58417 maechler 840
	/* If the format includes %Z or %z
52762 ripley 841
	   we need to try to set TZ accordingly */
842
	int needTZ = 0;
843
	for(i = 0; i < m; i++) {
844
	    const char *p = CHAR(STRING_ELT(sformat, i));
845
	    if (strstr(p, "%Z") || strstr(p, "%z")) {needTZ = 1; break;}
846
	}
847
	if(needTZ) settz = set_tz(tz1, oldtz);
848
    }
849
 
51353 ripley 850
    /* workaround for glibc/FreeBSD/MacOS X bugs in strftime: they have
851
       non-POSIX/C99 time zone components
32716 ripley 852
     */
853
    memset(&tm, 0, sizeof(tm));
27974 ripley 854
 
37334 ripley 855
    /* coerce fields to integer or real, find length of longest one */
10543 ripley 856
    for(i = 0; i < 9; i++) {
60241 ripley 857
	nlen[i] = XLENGTH(VECTOR_ELT(x, i));
10543 ripley 858
	if(nlen[i] > n) n = nlen[i];
45446 ripley 859
	SET_VECTOR_ELT(x, i, coerceVector(VECTOR_ELT(x, i),
37334 ripley 860
					  i > 0 ? INTSXP : REALSXP));
10543 ripley 861
    }
58417 maechler 862
    if(n > 0) {
863
	for(i = 0; i < 9; i++)
864
	    if(nlen[i] == 0)
60844 ripley 865
		error(_("zero-length component in non-empty \"POSIXlt\" structure"));
58417 maechler 866
    }
10543 ripley 867
    if(n > 0) N = (m > n) ? m:n; else N = 0;
868
    PROTECT(ans = allocVector(STRSXP, N));
869
    for(i = 0; i < N; i++) {
37334 ripley 870
	double secs = REAL(VECTOR_ELT(x, 0))[i%nlen[0]], fsecs = floor(secs);
59170 ripley 871
	tm.tm_sec   = (int) fsecs;
10543 ripley 872
	tm.tm_min   = INTEGER(VECTOR_ELT(x, 1))[i%nlen[1]];
873
	tm.tm_hour  = INTEGER(VECTOR_ELT(x, 2))[i%nlen[2]];
874
	tm.tm_mday  = INTEGER(VECTOR_ELT(x, 3))[i%nlen[3]];
875
	tm.tm_mon   = INTEGER(VECTOR_ELT(x, 4))[i%nlen[4]];
876
	tm.tm_year  = INTEGER(VECTOR_ELT(x, 5))[i%nlen[5]];
877
	tm.tm_wday  = INTEGER(VECTOR_ELT(x, 6))[i%nlen[6]];
878
	tm.tm_yday  = INTEGER(VECTOR_ELT(x, 7))[i%nlen[7]];
879
	tm.tm_isdst = INTEGER(VECTOR_ELT(x, 8))[i%nlen[8]];
37334 ripley 880
	if(!R_FINITE(secs) || tm.tm_min == NA_INTEGER ||
10543 ripley 881
	   tm.tm_hour == NA_INTEGER || tm.tm_mday == NA_INTEGER ||
882
	   tm.tm_mon == NA_INTEGER || tm.tm_year == NA_INTEGER) {
883
	    SET_STRING_ELT(ans, i, NA_STRING);
884
	} else {
885
	    if(validate_tm(&tm) < 0) SET_STRING_ELT(ans, i, NA_STRING);
886
	    else {
41807 rgentlem 887
		const char *q = CHAR(STRING_ELT(sformat, i%m));
59170 ripley 888
		int n = (int) strlen(q) + 50;
51398 ripley 889
		char buf2[n];
51357 ripley 890
#ifdef Win32
51353 ripley 891
		/* We want to override Windows' TZ names */
892
		p = strstr(q, "%Z");
893
		if (p) {
894
		    memset(buf2, 0, n);
895
		    strncpy(buf2, q, p - q);
896
		    strcat(buf2, tm.tm_isdst > 0 ? tzname[1] : tzname[0]);
897
		    strcat(buf2, p+2);
51356 ripley 898
		} else
58417 maechler 899
#endif
51365 ripley 900
		    strcpy(buf2, q);
901
 
37334 ripley 902
		p = strstr(q, "%OS");
903
		if(p) {
51353 ripley 904
		    /* FIXME some of this should be outside the loop */
37439 ripley 905
		    int ns, nused = 4;
37334 ripley 906
		    char *p2 = strstr(buf2, "%OS");
907
		    *p2 = '\0';
908
		    ns = *(p+3) - '0';
37439 ripley 909
		    if(ns < 0 || ns > 9) { /* not a digit */
54049 ripley 910
			ns = asInteger(GetOption1(install("digits.secs")));
37439 ripley 911
			if(ns == NA_INTEGER) ns = 0;
912
			nused = 3;
913
		    }
37334 ripley 914
		    if(ns > 6) ns = 6;
37439 ripley 915
		    if(ns > 0) {
55860 ripley 916
			/* truncate to avoid nuisances such as PR#14579 */
917
			double s = secs, t = pow(10.0, (double) ns);
918
			s = ((int) (s*t))/t;
919
			sprintf(p2, "%0*.*f", ns+3, ns, s);
37439 ripley 920
			strcat(buf2, p+nused);
921
		    } else {
922
			strcat(p2, "%S");
923
			strcat(buf2, p+nused);
924
		    }
37334 ripley 925
		}
926
		strftime(buff, 256, buf2, &tm);
12256 pd 927
		if(UseTZ && !isNull(tz)) {
928
		    int i = 0;
929
		    if(LENGTH(tz) == 3) {
930
			if(tm.tm_isdst > 0) i = 2;
45446 ripley 931
			else if(tm.tm_isdst == 0) i = 1;
12256 pd 932
			else i = 0; /* Use base timezone name */
933
		    }
934
		    p = CHAR(STRING_ELT(tz, i));
935
		    if(strlen(p)) {
936
			strcat(buff, " ");
937
			strcat(buff, p);
938
		    }
939
		}
10543 ripley 940
		SET_STRING_ELT(ans, i, mkChar(buff));
941
	    }
942
	}
943
    }
37334 ripley 944
    UNPROTECT(2);
52762 ripley 945
    if(settz) reset_tz(oldtz);
10543 ripley 946
    return ans;
947
}
948
 
16537 ripley 949
static void glibc_fix(struct tm *tm, int *invalid)
950
{
951
    /* set mon and mday which glibc does not always set.
952
       Use current year/... if none has been specified.
953
 
954
       Specifying mon but not mday nor yday is invalid.
955
    */
956
    time_t t = time(NULL);
957
    struct tm *tm0;
958
    int tmp;
959
#ifndef HAVE_POSIX_LEAPSECONDS
37077 ripley 960
    t -= n_leapseconds;
16537 ripley 961
#endif
962
    tm0 = localtime(&t);
963
    if(tm->tm_year == NA_INTEGER) tm->tm_year = tm0->tm_year;
19361 ripley 964
    if(tm->tm_mon != NA_INTEGER && tm->tm_mday != NA_INTEGER) return;
965
    /* at least one of the month and the day of the month is missing */
16537 ripley 966
    if(tm->tm_yday != NA_INTEGER) {
967
	/* since we have yday, let that take precedence over mon/mday */
968
	int yday = tm->tm_yday, mon = 0;
40871 ripley 969
	while(yday >= (tmp = days_in_month[mon] +
16537 ripley 970
		      ((mon==1 && isleap(1900+tm->tm_year))? 1 : 0))) {
971
	    yday -= tmp;
972
	    mon++;
973
	}
974
	tm->tm_mon = mon;
975
	tm->tm_mday = yday + 1;
976
    } else {
977
	if(tm->tm_mday == NA_INTEGER) {
978
	    if(tm->tm_mon != NA_INTEGER) {
979
		*invalid = 1;
980
		return;
981
	    } else tm->tm_mday = tm0->tm_mday;
982
	}
983
	if(tm->tm_mon == NA_INTEGER) tm->tm_mon = tm0->tm_mon;
984
    }
985
}
986
 
987
 
36990 ripley 988
SEXP attribute_hidden do_strptime(SEXP call, SEXP op, SEXP args, SEXP env)
10543 ripley 989
{
40412 ripley 990
    SEXP x, sformat, ans, ansnames, klass, stz, tzone;
60241 ripley 991
    int invalid, isgmt = 0, settz = 0, offset;
51374 ripley 992
    struct tm tm, tm2, *ptm = &tm;
41807 rgentlem 993
    const char *tz = NULL;
994
    char oldtz[20] = "";
37395 ripley 995
    double psecs = 0.0;
60241 ripley 996
    R_xlen_t i, n, m, N;
10543 ripley 997
 
998
    checkArity(op, args);
999
    if(!isString((x= CAR(args))))
35264 ripley 1000
	error(_("invalid '%s' argument"), "x");
60241 ripley 1001
    if(!isString((sformat = CADR(args))) || XLENGTH(sformat) == 0)
35264 ripley 1002
	error(_("invalid '%s' argument"), "x");
36040 ripley 1003
    if(!isString((stz = CADDR(args))) || LENGTH(stz) != 1)
1004
	error(_("invalid '%s' value"), "tz");
1005
    tz = CHAR(STRING_ELT(stz, 0));
40406 ripley 1006
    if(strlen(tz) == 0) {
1007
	/* do a direct look up here as this does not otherwise
1008
	   work on Windows */
1009
	char *p = getenv("TZ");
52570 murdoch 1010
	if(p) {
1011
	    stz = mkString(p);
1012
	    tz = CHAR(STRING_ELT(stz, 0));
1013
	}
40406 ripley 1014
    }
52570 murdoch 1015
    PROTECT(stz); /* it might be new */
36040 ripley 1016
    if(strcmp(tz, "GMT") == 0  || strcmp(tz, "UTC") == 0) isgmt = 1;
40406 ripley 1017
    if(!isgmt && strlen(tz) > 0) settz = set_tz(tz, oldtz);
36040 ripley 1018
 
60241 ripley 1019
    n = XLENGTH(x); m = XLENGTH(sformat);
1020
    if(n > 0) N = (m > n) ? m : n; else N = 0;
10543 ripley 1021
 
1022
    PROTECT(ans = allocVector(VECSXP, 9));
1023
    for(i = 0; i < 9; i++)
37334 ripley 1024
	SET_VECTOR_ELT(ans, i, allocVector(i > 0 ? INTSXP : REALSXP, N));
10543 ripley 1025
 
1026
    PROTECT(ansnames = allocVector(STRSXP, 9));
1027
    for(i = 0; i < 9; i++)
1028
	SET_STRING_ELT(ansnames, i, mkChar(ltnames[i]));
1029
 
1030
 
1031
    for(i = 0; i < N; i++) {
16537 ripley 1032
	/* for glibc's sake. That only sets some unspecified fields,
1033
	   sometimes. */
1034
	tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
45446 ripley 1035
	tm.tm_year = tm.tm_mon = tm.tm_mday = tm.tm_yday =
31511 ripley 1036
	    tm.tm_wday = NA_INTEGER;
1037
	tm.tm_isdst = -1;
51374 ripley 1038
	offset = NA_INTEGER;
10543 ripley 1039
	invalid = STRING_ELT(x, i%n) == NA_STRING ||
37398 ripley 1040
	    !R_strptime(CHAR(STRING_ELT(x, i%n)),
51374 ripley 1041
			CHAR(STRING_ELT(sformat, i%m)), &tm, &psecs, &offset);
10543 ripley 1042
	if(!invalid) {
18603 ripley 1043
	    /* Solaris sets missing fields to 0 */
18557 ripley 1044
	    if(tm.tm_mday == 0) tm.tm_mday = NA_INTEGER;
16537 ripley 1045
	    if(tm.tm_mon == NA_INTEGER || tm.tm_mday == NA_INTEGER
1046
	       || tm.tm_year == NA_INTEGER)
1047
		glibc_fix(&tm, &invalid);
10543 ripley 1048
	    tm.tm_isdst = -1;
51374 ripley 1049
	    if (offset != NA_INTEGER) {
1050
		/* we know the offset, but not the timezone
58417 maechler 1051
		   so all we can do is to convert to time_t,
51374 ripley 1052
		   adjust and convert back */
1053
		double t0;
1054
		memcpy(&tm2, &tm, sizeof(struct tm));
1055
		t0 = mktime0(&tm2, 0);
1056
		if (t0 != -1) {
1057
		    t0 -= offset; /* offset = -0800 is Seattle */
1058
		    ptm = localtime0(&t0, 1-isgmt, &tm2);
1059
		} else invalid = 1;
1060
	    } else {
1061
		/* we do want to set wday, yday, isdst, but not to
1062
		   adjust structure at DST boundaries */
1063
		memcpy(&tm2, &tm, sizeof(struct tm));
1064
		mktime0(&tm2, 1-isgmt); /* set wday, yday, isdst */
1065
		tm.tm_wday = tm2.tm_wday;
1066
		tm.tm_yday = tm2.tm_yday;
1067
		tm.tm_isdst = isgmt ? 0: tm2.tm_isdst;
1068
	    }
1069
	    invalid = validate_tm(&tm) != 0;
10543 ripley 1070
	}
51374 ripley 1071
	makelt(ptm, ans, i, !invalid, psecs - floor(psecs));
10543 ripley 1072
    }
40406 ripley 1073
 
10543 ripley 1074
    setAttrib(ans, R_NamesSymbol, ansnames);
39866 duncan 1075
    PROTECT(klass = allocVector(STRSXP, 2));
51712 ripley 1076
    SET_STRING_ELT(klass, 0, mkChar("POSIXlt"));
1077
    SET_STRING_ELT(klass, 1, mkChar("POSIXt"));
39866 duncan 1078
    classgets(ans, klass);
40412 ripley 1079
    if (isgmt) {
41894 ripley 1080
	PROTECT(tzone = mkString(tz));
40412 ripley 1081
	setAttrib(ans, install("tzone"), tzone);
1082
	UNPROTECT(1);
1083
    } else if(strlen(tz)) {
1084
	PROTECT(tzone = allocVector(STRSXP, 3));
1085
	SET_STRING_ELT(tzone, 0, mkChar(tz));
1086
	SET_STRING_ELT(tzone, 1, mkChar(tzname[0]));
1087
	SET_STRING_ELT(tzone, 2, mkChar(tzname[1]));
1088
	setAttrib(ans, install("tzone"), tzone);
1089
	UNPROTECT(1);
1090
    }
1091
    if(settz) reset_tz(oldtz);
1092
 
52570 murdoch 1093
    UNPROTECT(4);
10543 ripley 1094
    return ans;
1095
}
28072 ripley 1096
 
36990 ripley 1097
SEXP attribute_hidden do_D2POSIXlt(SEXP call, SEXP op, SEXP args, SEXP env)
28072 ripley 1098
{
39866 duncan 1099
    SEXP x, ans, ansnames, klass;
60241 ripley 1100
    R_xlen_t n, i;
1101
    int valid, day, y, tmp, mon;
28072 ripley 1102
    struct tm tm;
1103
 
1104
    checkArity(op, args);
1105
    PROTECT(x = coerceVector(CAR(args), REALSXP));
60241 ripley 1106
    n = XLENGTH(x);
28072 ripley 1107
    PROTECT(ans = allocVector(VECSXP, 9));
1108
    for(i = 0; i < 9; i++)
37334 ripley 1109
	SET_VECTOR_ELT(ans, i, allocVector(i > 0 ? INTSXP : REALSXP, n));
28072 ripley 1110
 
1111
    PROTECT(ansnames = allocVector(STRSXP, 9));
1112
    for(i = 0; i < 9; i++)
1113
	SET_STRING_ELT(ansnames, i, mkChar(ltnames[i]));
1114
 
1115
    for(i = 0; i < n; i++) {
1116
	if(R_FINITE(REAL(x)[i])) {
53541 ripley 1117
	    day = (int) floor(REAL(x)[i]);
28072 ripley 1118
	    tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
1119
	    /* weekday: 1970-01-01 was a Thursday */
1120
	    if ((tm.tm_wday = ((4 + day) % 7)) < 0) tm.tm_wday += 7;
1121
 
1122
	    /* year & day within year */
1123
	    y = 1970;
1124
	    if (day >= 0)
1125
		for ( ; day >= (tmp = days_in_year(y)); day -= tmp, y++);
1126
	    else
1127
		for ( ; day < 0; --y, day += days_in_year(y) );
28584 ripley 1128
 
28072 ripley 1129
	    y = tm.tm_year = y - 1900;
1130
	    tm.tm_yday = day;
1131
 
1132
	    /* month within year */
1133
	    for (mon = 0;
28584 ripley 1134
		 day >= (tmp = (days_in_month[mon]) +
28072 ripley 1135
			 ((mon==1 && isleap(y+1900))?1:0));
1136
		 day -= tmp, mon++);
1137
	    tm.tm_mon = mon;
1138
	    tm.tm_mday = day + 1;
1139
	    tm.tm_isdst = 0; /* no dst in GMT */
1140
 
1141
	    valid = 1;
1142
	} else valid = 0;
37334 ripley 1143
	makelt(&tm, ans, i, valid, 0.0);
28072 ripley 1144
    }
1145
    setAttrib(ans, R_NamesSymbol, ansnames);
39866 duncan 1146
    PROTECT(klass = allocVector(STRSXP, 2));
51712 ripley 1147
    SET_STRING_ELT(klass, 0, mkChar("POSIXlt"));
1148
    SET_STRING_ELT(klass, 1, mkChar("POSIXt"));
39866 duncan 1149
    classgets(ans, klass);
39051 ripley 1150
    setAttrib(ans, install("tzone"), mkString("UTC"));
28072 ripley 1151
    UNPROTECT(4);
1152
 
1153
    return ans;
1154
}
1155
 
36990 ripley 1156
SEXP attribute_hidden do_POSIXlt2D(SEXP call, SEXP op, SEXP args, SEXP env)
28072 ripley 1157
{
39866 duncan 1158
    SEXP x, ans, klass;
60241 ripley 1159
    R_xlen_t i, n = 0, nlen[9];
28072 ripley 1160
    struct tm tm;
1161
 
1162
    checkArity(op, args);
37334 ripley 1163
    PROTECT(x = duplicate(CAR(args)));
28072 ripley 1164
    if(!isVectorList(x) || LENGTH(x) != 9)
35264 ripley 1165
	error(_("invalid '%s' argument"), "x");
28072 ripley 1166
 
1167
    for(i = 3; i < 6; i++)
60241 ripley 1168
	if((nlen[i] = XLENGTH(VECTOR_ELT(x, i))) > n) n = nlen[i];
1169
    if((nlen[8] = XLENGTH(VECTOR_ELT(x, 8))) > n) n = nlen[8];
28072 ripley 1170
    if(n > 0) {
1171
	for(i = 3; i < 6; i++)
1172
	    if(nlen[i] == 0)
60844 ripley 1173
		error(_("zero-length component in non-empty \"POSIXlt\" structure"));
28072 ripley 1174
	if(nlen[8] == 0)
60844 ripley 1175
	    error(_("zero-length component in non-empty \"POSIXlt\" structure"));
28072 ripley 1176
    }
37334 ripley 1177
    /* coerce relevant fields to integer */
1178
    for(i = 3; i < 6; i++)
28072 ripley 1179
	SET_VECTOR_ELT(x, i, coerceVector(VECTOR_ELT(x, i), INTSXP));
1180
 
1181
    PROTECT(ans = allocVector(REALSXP, n));
1182
    for(i = 0; i < n; i++) {
1183
	tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
1184
	tm.tm_mday  = INTEGER(VECTOR_ELT(x, 3))[i%nlen[3]];
1185
	tm.tm_mon   = INTEGER(VECTOR_ELT(x, 4))[i%nlen[4]];
1186
	tm.tm_year  = INTEGER(VECTOR_ELT(x, 5))[i%nlen[5]];
1187
	/* mktime ignores tm.tm_wday and tm.tm_yday */
1188
	tm.tm_isdst = 0;
28584 ripley 1189
	if(tm.tm_mday == NA_INTEGER || tm.tm_mon == NA_INTEGER ||
28072 ripley 1190
	   tm.tm_year == NA_INTEGER || validate_tm(&tm) < 0)
1191
	    REAL(ans)[i] = NA_REAL;
35585 ripley 1192
	else {
43843 ripley 1193
	    /* -1 must be error as seconds were zeroed */
35585 ripley 1194
	    double tmp = mktime00(&tm);
37334 ripley 1195
	    REAL(ans)[i] = (tmp == -1) ? NA_REAL : tmp/86400;
35585 ripley 1196
	}
28072 ripley 1197
    }
1198
 
41894 ripley 1199
    PROTECT(klass = mkString("Date"));
39866 duncan 1200
    classgets(ans, klass);
37334 ripley 1201
    UNPROTECT(3);
28072 ripley 1202
    return ans;
1203
}