[tz] [PROPOSED PATCH 1/4] Have zdump output gmtoff= even on platforms lacking TM_GMTOFF.

Paul Eggert eggert at cs.ucla.edu
Mon Sep 22 05:53:34 UTC 2014


* zdump.c (adjusted_yday, gmtoff): New functions.
(show): Use new function gmtoff to output gmtoff= even on
platforms that do not define TM_GMTOFF.
* NEWS: Document this.
---
 NEWS    |  3 +++
 zdump.c | 49 ++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 45 insertions(+), 7 deletions(-)

diff --git a/NEWS b/NEWS
index 21e85a7..618ddb7 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,9 @@ Unreleased, experimental changes
 
   Changes affecting code
 
+    zdump -V and -v now output gmtoff= values on all platforms,
+    not merely on platforms defining TM_GMTOFF.
+
     The tz library's localtime and mktime functions now set tzname to a value
     appropriate for the requested time stamp, and zdump now uses this
     on platforms not defining TM_ZONE, fixing a 2014g regression.
diff --git a/zdump.c b/zdump.c
index 0aa94fc..92dd3c1 100644
--- a/zdump.c
+++ b/zdump.c
@@ -851,19 +851,54 @@ delta(struct tm * newp, struct tm *oldp)
 	return result;
 }
 
+/* Return A->tm_yday, adjusted to compare it fairly to B->tm_yday.
+  Assume A and B differ by at most one year.  */
+static int
+adjusted_yday(struct tm const *a, struct tm const *b)
+{
+  int yday = a->tm_yday;
+  if (b->tm_year < a->tm_year)
+    yday += 365 + isleap_sum(b->tm_year, TM_YEAR_BASE);
+  return yday;
+}
+
+/* If A is the broken-down local time and B the broken-down UTC for
+   the same instant, return A's UTC offset in seconds, where positive
+   offsets are east of Greenwich.  On failure, return LONG_MIN.  */
+static long
+gmtoff(struct tm const *a, struct tm const *b)
+{
+#ifdef TM_GMTOFF
+  return a->TM_GMTOFF;
+#else
+  if (! b)
+    return LONG_MIN;
+  else {
+    int ayday = adjusted_yday(a, b);
+    int byday = adjusted_yday(b, a);
+    int days = ayday - byday;
+    long hours = a->tm_hour - b->tm_hour + 24 * days;
+    long minutes = a->tm_min - b->tm_min + 60 * hours;
+    long seconds = a->tm_sec - b->tm_sec + 60 * minutes;
+    return seconds;
+  }
+#endif
+}
+
 static void
 show(timezone_t tz, char *zone, time_t t, bool v)
 {
 	register struct tm *	tmp;
-	struct tm tm;
+	register struct tm *	gmtmp;
+	struct tm tm, gmtm;
 
 	printf("%-*s  ", longest, zone);
 	if (v) {
-		tmp = my_gmtime_r(&t, &tm);
-		if (tmp == NULL) {
+		gmtmp = my_gmtime_r(&t, &gmtm);
+		if (gmtmp == NULL) {
 			printf(tformat(), t);
 		} else {
-			dumptime(tmp);
+			dumptime(gmtmp);
 			printf(" UT");
 		}
 		printf(" = ");
@@ -874,10 +909,10 @@ show(timezone_t tz, char *zone, time_t t, bool v)
 		if (*abbr(tmp) != '\0')
 			printf(" %s", abbr(tmp));
 		if (v) {
+			long off = gmtoff(tmp, gmtmp);
 			printf(" isdst=%d", tmp->tm_isdst);
-#ifdef TM_GMTOFF
-			printf(" gmtoff=%ld", tmp->TM_GMTOFF);
-#endif /* defined TM_GMTOFF */
+			if (off != LONG_MIN)
+			  printf(" gmtoff=%ld", off);
 		}
 	}
 	printf("\n");
-- 
1.9.3



More information about the tz mailing list