Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/lib/libutil Improved handling of local times.
details: https://anonhg.NetBSD.org/src/rev/85f4d1df552b
branches: trunk
changeset: 332776:85f4d1df552b
user: apb <apb%NetBSD.org@localhost>
date: Wed Oct 08 17:38:28 2014 +0000
description:
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.
diffstat:
lib/libutil/parsedate.y | 82 ++++++++++++++++++++++--------------------------
1 files changed, 37 insertions(+), 45 deletions(-)
diffs (135 lines):
diff -r 4b005ec572d7 -r 85f4d1df552b lib/libutil/parsedate.y
--- a/lib/libutil/parsedate.y Wed Oct 08 17:23:03 2014 +0000
+++ b/lib/libutil/parsedate.y Wed Oct 08 17:38:28 2014 +0000
@@ -14,7 +14,7 @@
#include <sys/cdefs.h>
#ifdef __RCSID
-__RCSID("$NetBSD: parsedate.y,v 1.19 2014/10/08 14:43:48 apb Exp $");
+__RCSID("$NetBSD: parsedate.y,v 1.20 2014/10/08 17:38:28 apb Exp $");
#endif
#include <stdio.h>
@@ -42,6 +42,7 @@
#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 @@
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 @@
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 @@
#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 @@
saved_errno = errno;
errno = 0;
- if (now == NULL || zone == NULL) {
+ if (now == NULL) {
now = &nowt;
+ (void)time(&nowt);
+ }
+ if (zone == NULL) {
zone = &zonet;
- (void)time(&nowt);
-
- gmt_ptr = gmtime_r(now, &gmt);
+ 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;
Home |
Main Index |
Thread Index |
Old Index