Module Name: src Committed By: snj Date: Sat Oct 11 16:56:21 UTC 2014
Modified Files: src/lib/libutil [netbsd-7]: parsedate.y Log Message: Pull up following revision(s) (requested by apb in ticket #135): lib/libutil/parsedate.y: revision 1.20 Improved handling of local times. * A magic value USE_LOCAL_TIME (defined as 99999) may be passed as the Timezone to Convert(), instructing it to use mktime() to work in the local time zone, instead of using mktime_z to work in UTC (and then adding the specified timezone offset). * Some old code is removed now that there's no need to find the local timezone offset. * Allow either one or both of the now and zone arguments to parsedate() to be NULL, treating them independently. Previously, if either one was NULL, the other was ignored. * If the zone argument is specified, then the current date is calculated in the specified zone, not in local time. Also add some disabled debug code. This should fix PR lib/47916. To generate a diff of this commit: cvs rdiff -u -r1.16.6.3 -r1.16.6.4 src/lib/libutil/parsedate.y Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libutil/parsedate.y diff -u src/lib/libutil/parsedate.y:1.16.6.3 src/lib/libutil/parsedate.y:1.16.6.4 --- src/lib/libutil/parsedate.y:1.16.6.3 Sat Oct 11 16:51:23 2014 +++ src/lib/libutil/parsedate.y Sat Oct 11 16:56:21 2014 @@ -14,7 +14,7 @@ #include <sys/cdefs.h> #ifdef __RCSID -__RCSID("$NetBSD: parsedate.y,v 1.16.6.3 2014/10/11 16:51:23 snj Exp $"); +__RCSID("$NetBSD: parsedate.y,v 1.16.6.4 2014/10/11 16:56:21 snj Exp $"); #endif #include <stdio.h> @@ -42,6 +42,7 @@ __RCSID("$NetBSD: parsedate.y,v 1.16.6.3 #define HOUR(x) ((time_t)(x) * 60) #define SECSPERDAY (24L * 60L * 60L) +#define USE_LOCAL_TIME 99999 /* special case for Convert() and yyTimezone */ /* ** An entry in the lexical lookup table. @@ -618,7 +619,8 @@ Convert( time_t Hours, /* Hour of day [0-24] */ time_t Minutes, /* Minute of hour [0-59] */ time_t Seconds, /* Second of minute [0-60] */ - time_t Timezone, /* Timezone as minutes east of UTC */ + time_t Timezone, /* Timezone as minutes east of UTC, + * or USE_LOCAL_TIME special case */ MERIDIAN Meridian, /* Hours are am/pm/24 hour clock */ DSTMODE DSTmode /* DST on/off/maybe */ ) @@ -638,9 +640,25 @@ Convert( default: tm.tm_isdst = -1; break; } - /* We rely on mktime_z(NULL, ...) working in UTC, not in local time. */ - result = mktime_z(NULL, &tm); - result += Timezone * 60; + if (Timezone == USE_LOCAL_TIME) { + result = mktime(&tm); + } else { + /* We rely on mktime_z(NULL, ...) working in UTC */ + result = mktime_z(NULL, &tm); + result += Timezone * 60; + } + +#if PARSEDATE_DEBUG + fprintf(stderr, "%s(M=%jd D=%jd Y=%jd H=%jd M=%jd S=%jd Z=%jd" + " mer=%d DST=%d)", + __func__, + (intmax_t)Month, (intmax_t)Day, (intmax_t)Year, + (intmax_t)Hours, (intmax_t)Minutes, (intmax_t)Seconds, + (intmax_t)Timezone, (int)Meridian, (int)DSTmode); + fprintf(stderr, " -> %jd", (intmax_t)result); + fprintf(stderr, " %s", ctime(&result)); +#endif + return result; } @@ -878,31 +896,10 @@ yylex(YYSTYPE *yylval, const char **yyIn #define TM_YEAR_ORIGIN 1900 -/* Yield A - B, measured in seconds. */ -static time_t -difftm (struct tm *a, struct tm *b) -{ - int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); - int by = b->tm_year + (TM_YEAR_ORIGIN - 1); - int days = ( - /* difference in day of year */ - a->tm_yday - b->tm_yday - /* + intervening leap days */ - + ((ay >> 2) - (by >> 2)) - - (ay/100 - by/100) - + ((ay/100 >> 2) - (by/100 >> 2)) - /* + difference in years * 365 */ - + (long)(ay-by) * 365 - ); - return ((time_t)60*(60*(24*days + (a->tm_hour - b->tm_hour)) - + (a->tm_min - b->tm_min)) - + (a->tm_sec - b->tm_sec)); -} - time_t parsedate(const char *p, const time_t *now, const int *zone) { - struct tm gmt, local, *gmt_ptr, *tm; + struct tm local, *tm; time_t nowt; int zonet; time_t Start; @@ -913,29 +910,24 @@ parsedate(const char *p, const time_t *n saved_errno = errno; errno = 0; - if (now == NULL || zone == NULL) { + if (now == NULL) { now = &nowt; - zone = &zonet; (void)time(&nowt); - - gmt_ptr = gmtime_r(now, &gmt); + } + if (zone == NULL) { + zone = &zonet; + zonet = USE_LOCAL_TIME; if ((tm = localtime_r(now, &local)) == NULL) return -1; - - if (gmt_ptr != NULL) - zonet = difftm(&gmt, &local) / 60; - else - /* We are on a system like VMS, where the system clock is - in local time and the system has no concept of timezones. - Hopefully we can fake this out (for the case in which the - user specifies no timezone) by just saying the timezone - is zero. */ - zonet = 0; - - if (local.tm_isdst) - zonet += 60; } else { - if ((tm = localtime_r(now, &local)) == NULL) + /* + * Should use the specified zone, not localtime. + * Fake it using gmtime and arithmetic. + * This is good enough because we use only the year/month/day, + * not other fields of struct tm. + */ + time_t fake = *now + (*zone * 60); + if ((tm = gmtime_r(&fake, &local)) == NULL) return -1; } param.yyYear = tm->tm_year + 1900;