[tz] [PATCH] Remove attempt to support floating-point time_t.

Paul Eggert eggert at cs.ucla.edu
Mon Aug 12 08:47:17 UTC 2013


Here's a proposed patch to remove the tz code's attempt to support
floating-point time_t.  This has the benefit of simplifying
the code and making maintenance easier.  Comments welcome
(particularly if you know of any real systems that have
floating-point time_t!).  I've pushed this to the experimental
github repository.
-----
It wasn't tested and probably never worked, no platform used it,
and the latest POSIX no longer allows it.
* Makefile (typecheck): Don't check time_t being 'double'.
* Theory: Document the change.
* difftime.c (difftime):
* localtime.c (differ_by_repeat, tzload, timesub, time2sub):
* private.h (time_t_min, time_t_max):
* zdump.c (absolute_min_time, absolute_max_time, tformat):
Don't try to support floating-point time_t.
* localtime.c, private.h, zdump.c: Don't include float.h.
* localtime.c (truncate_time, double_to_time):
* private.h (TYPE_INTEGRAL):
* zdump.c (checkabsolutes):
Remove; no longer needed.  All uses removed.
* zdump.8 (LIMITATIONS): Remove discussion of floating-point time_t.
---
 Makefile    |  3 +--
 Theory      |  9 ++++-----
 difftime.c  | 10 +---------
 localtime.c | 62 ++++++-------------------------------------------------------
 private.h   | 28 ++--------------------------
 zdump.8     |  7 -------
 zdump.c     | 37 ++----------------------------------
 7 files changed, 16 insertions(+), 140 deletions(-)

diff --git a/Makefile b/Makefile
index 8b033a6..db7f56e 100644
--- a/Makefile
+++ b/Makefile
@@ -121,7 +121,6 @@ LDLIBS=
 #  -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU=1
 #	if you do not want run time warnings about formats that may cause
 #	year 2000 grief
-#  -DTIME_T_FLOATING=1 if your time_t (or time_tz) is floating point
 #  -Dtime_tz=\"T\" to use T as the time_t type, rather than the system time_t
 #  -DTZ_DOMAIN=\"foo\" to use "foo" for gettext domain name; default is "tz"
 #  -TTZ_DOMAINDIR=\"/path\" to use "/path" for gettext directory;
@@ -541,7 +540,7 @@ tzdata$(VERSION).tar.gz.asc: tzdata$(VERSION).tar.gz
 
 typecheck:
 		make clean
-		for i in "long long" unsigned double; \
+		for i in "long long" unsigned; \
 		do \
 			make CFLAGS="-DTYPECHECK -D__time_t_defined -D_TIME_T \"-Dtime_t=$$i\"" ; \
 			./zdump -v Europe/Rome ; \
diff --git a/Theory b/Theory
index 1b5374a..b4bd4c2 100644
--- a/Theory
+++ b/Theory
@@ -104,11 +104,10 @@ POSIX has the following properties and limitations.
 	new implementations these days typically use a signed 64-bit integer.
 	Unsigned 32-bit integers are used on one or two platforms,
 	and 36-bit integers are also used occasionally.
-	Although POSIX.1-2013 requires time_t to be an integer type,
-	earlier POSIX versions also allowed time_t to be a floating-point type.
-	No known platforms have a floating-point time_t and although
-	the tz code attempts to support floating-point time_t this has not
-	been tested and will probably be removed at some point.
+	Although earlier POSIX versions allowed time_t to be a
+	floating-point type, this was not supported by any practical
+	systems, and POSIX.1-2013 and the tz code both require time_t
+	to be an integer type.
 
 These are the extensions that have been made to the POSIX functions:
 
diff --git a/difftime.c b/difftime.c
index fcd18ce..449cdf0 100644
--- a/difftime.c
+++ b/difftime.c
@@ -5,7 +5,7 @@
 
 /*LINTLIBRARY*/
 
-#include "private.h"	/* for time_t, TYPE_INTEGRAL, and TYPE_SIGNED */
+#include "private.h"	/* for time_t and TYPE_SIGNED */
 
 double ATTRIBUTE_CONST
 difftime(const time_t time1, const time_t time0)
@@ -16,15 +16,8 @@ difftime(const time_t time1, const time_t time0)
 	*/
 	if (sizeof (double) > sizeof (time_t))
 		return (double) time1 - (double) time0;
-	if (!TYPE_INTEGRAL(time_t)) {
-		/*
-		** time_t is floating.
-		*/
-		return time1 - time0;
-	}
 	if (!TYPE_SIGNED(time_t)) {
 		/*
-		** time_t is integral and unsigned.
 		** The difference of two unsigned values can't overflow
 		** if the minuend is greater than or equal to the subtrahend.
 		*/
@@ -33,7 +26,6 @@ difftime(const time_t time1, const time_t time0)
 		else	return -(double) (time0 - time1);
 	}
 	/*
-	** time_t is integral and signed.
 	** Handle cases where both time1 and time0 have the same sign
 	** (meaning that their difference cannot overflow).
 	*/
diff --git a/localtime.c b/localtime.c
index 9600901..5312ad9 100644
--- a/localtime.c
+++ b/localtime.c
@@ -13,7 +13,6 @@
 #include "private.h"
 #include "tzfile.h"
 #include "fcntl.h"
-#include "float.h"	/* for FLT_MAX and DBL_MAX */
 
 #ifndef TZ_ABBR_MAX_LEN
 #define TZ_ABBR_MAX_LEN	16
@@ -318,9 +317,8 @@ settzname(void)
 static int
 differ_by_repeat(const time_t t1, const time_t t0)
 {
-	if (TYPE_INTEGRAL(time_t) &&
-		TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
-			return 0;
+	if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
+		return 0;
 	return t1 - t0 == SECSPERREPEAT;
 }
 
@@ -527,9 +525,9 @@ tzload(register const char *name, register struct state *const sp,
 		for (i = 0; i < nread; ++i)
 			up->buf[i] = p[i];
 		/*
-		** If this is a narrow integer time_t system, we're done.
+		** If this is a narrow time_t system, we're done.
 		*/
-		if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
+		if (stored >= (int) sizeof(time_t))
 			break;
 	}
 	if (doextend && nread > 2 &&
@@ -1254,35 +1252,6 @@ tzset(void)
 	settzname();
 }
 
-/* Return T with any fractional part discarded.  */
-static time_t
-truncate_time(time_t t)
-{
-	/*
-	** If time_t is floating-point, convert it to integer and
-	** back; this discards the fraction.  Avoid using <math.h>
-	** functions, as we don't want to depend on <math.h>.  Use <,
-	** not <=, when comparing against *_MIN and *_MAX values, as
-	** this avoids undefined behavior when, for example,
-	** INTMAX_MAX is converted to a larger time_t value before it
-	** is compared.
-	**
-	** On all platforms that we know of (1) it is safe to compare
-	** INTMAX_MIN and INTMAX_MAX to floating-point values without
-	** worrying about undefined behavior due to floating-point
-	** overflow on conversion, and (2) any time_t value outside
-	** intmax_t range is an integer so we can simply return it.
-	** We know of no simple, portable way to check these assumptions.
-	** If you know of a counterexample platform, please report a bug.
-	*/
-	if (!TYPE_INTEGRAL(time_t) && INTMAX_MIN < t && t < INTMAX_MAX) {
-		intmax_t i = t;
-		return i;
-	}
-
-	return t;
-}
-
 /*
 ** The easy way to behave "as if no library function calls" localtime
 ** is to not call it--so we drop its guts into "localsub", which can be
@@ -1318,8 +1287,7 @@ localsub(const time_t *const timep, const int_fast32_t offset,
 				seconds = sp->ats[0] - t;
 			else	seconds = t - sp->ats[sp->timecnt - 1];
 			--seconds;
-			years = (truncate_time (seconds / SECSPERREPEAT + 1)
-				 * YEARSPERREPEAT);
+			years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
 			seconds = years * AVGSECSPERYEAR;
 			if (t < sp->ats[0])
 				newt += seconds;
@@ -1457,18 +1425,6 @@ offtime(const time_t *const timep, const long offset)
 #endif /* defined STD_INSPIRED */
 
 /*
-** Convert T to time_t, truncating toward zero if time_t is integral.
-** On most platforms, double_to_time(0.5) returns 0; the exceptions are
-** the rare platforms where time_t is floating.
-*/
-
-static time_t
-double_to_time(double t)
-{
-	return t;
-}
-
-/*
 ** Return the number of leap years through the end of the given year
 ** where, to make the math easy, the answer for year zero is defined as zero.
 */
@@ -1549,9 +1505,8 @@ timesub(const time_t *const timep, const int_fast32_t offset,
 	}
 	{
 		register int_fast32_t	seconds;
-		register time_t		half_second = double_to_time(0.5);
 
-		seconds = tdays * SECSPERDAY + half_second;
+		seconds = tdays * SECSPERDAY;
 		tdays = seconds / SECSPERDAY;
 		rem += seconds - tdays * SECSPERDAY;
 	}
@@ -1811,11 +1766,6 @@ time2sub(struct tm *const tmp,
 	if (!TYPE_SIGNED(time_t)) {
 		lo = 0;
 		hi = lo - 1;
-	} else if (!TYPE_INTEGRAL(time_t)) {
-		if (sizeof(time_t) > sizeof(float))
-			hi = (time_t) DBL_MAX;
-		else	hi = (time_t) FLT_MAX;
-		lo = -hi;
 	} else {
 		lo = 1;
 		for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
diff --git a/private.h b/private.h
index 5f4384e..8c1cda7 100644
--- a/private.h
+++ b/private.h
@@ -74,7 +74,6 @@
 #include "sys/types.h"	/* for time_t */
 #include "stdio.h"
 #include "errno.h"
-#include "float.h"	/* for FLT_MAX and DBL_MAX */
 #include "string.h"
 #include "limits.h"	/* for CHAR_BIT et al. */
 #include "time.h"
@@ -318,37 +317,14 @@ const char *	scheck(const char * string, const char * format);
 
 /* The minimum and maximum finite time values.  */
 static time_t const time_t_min =
-  ((time_t) 0.5 == 0.5
-   ? (sizeof (time_t) == sizeof (float) ? (time_t) -FLT_MAX
-      : sizeof (time_t) == sizeof (double) ? (time_t) -DBL_MAX
-      : sizeof (time_t) == sizeof (long double) ? (time_t) -LDBL_MAX
-      : 0)
-#ifndef TIME_T_FLOATING
-   : (time_t) -1 < 0
+  (TYPE_SIGNED(time_t)
    ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
-#endif
    : 0);
 static time_t const time_t_max =
-  ((time_t) 0.5 == 0.5
-   ? (sizeof (time_t) == sizeof (float) ? (time_t) FLT_MAX
-      : sizeof (time_t) == sizeof (double) ? (time_t) DBL_MAX
-      : sizeof (time_t) == sizeof (long double) ? (time_t) LDBL_MAX
-      : -1)
-#ifndef TIME_T_FLOATING
-   : (time_t) -1 < 0
+  (TYPE_SIGNED(time_t)
    ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
-#endif
    : -1);
 
-/*
-** Since the definition of TYPE_INTEGRAL contains floating point numbers,
-** it cannot be used in preprocessor directives.
-*/
-
-#ifndef TYPE_INTEGRAL
-#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
-#endif /* !defined TYPE_INTEGRAL */
-
 #ifndef INT_STRLEN_MAXIMUM
 /*
 ** 302 / 1000 is log10(2.0) rounded up.
diff --git a/zdump.8 b/zdump.8
index f253e81..af3277d 100644
--- a/zdump.8
+++ b/zdump.8
@@ -57,13 +57,6 @@ the program cuts off verbose output near the starts of the years \-500 and 2500.
 Cut off verbose output at the start of the given time(s),
 given in decimal seconds since 1970-01-01 00:00:00 UTC.
 .SH LIMITATIONS
-The
-.B \-v
-and
-.B \-V
-options may not be used on systems with floating-point time_t values
-that are neither float nor double.
-.PP
 Time discontinuities are found by sampling the results returned by localtime
 at twelve-hour intervals.
 This works in all real-world cases;
diff --git a/zdump.c b/zdump.c
index be0a496..788020a 100644
--- a/zdump.c
+++ b/zdump.c
@@ -23,7 +23,6 @@
 #include "sys/types.h"	/* for time_t */
 #include "time.h"	/* for struct tm */
 #include "stdlib.h"	/* for exit, malloc, atoi */
-#include "float.h"	/* for FLT_MAX and DBL_MAX */
 #include "limits.h"	/* for CHAR_BIT, LLONG_MAX */
 #include "ctype.h"	/* for isalpha et al. */
 #ifndef isascii
@@ -193,26 +192,12 @@ extern char *	tzname[2];
 
 /* The minimum and maximum finite time values.  */
 static time_t const absolute_min_time =
-  ((time_t) 0.5 == 0.5
-   ? (sizeof (time_t) == sizeof (float) ? (time_t) -FLT_MAX
-      : sizeof (time_t) == sizeof (double) ? (time_t) -DBL_MAX
-      : sizeof (time_t) == sizeof (long double) ? (time_t) -LDBL_MAX
-      : 0)
-#ifndef TIME_T_FLOATING
-   : (time_t) -1 < 0
+  ((time_t) -1 < 0
    ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
-#endif
    : 0);
 static time_t const absolute_max_time =
-  ((time_t) 0.5 == 0.5
-   ? (sizeof (time_t) == sizeof (float) ? (time_t) FLT_MAX
-      : sizeof (time_t) == sizeof (double) ? (time_t) DBL_MAX
-      : sizeof (time_t) == sizeof (long double) ? (time_t) LDBL_MAX
-      : -1)
-#ifndef TIME_T_FLOATING
-   : (time_t) -1 < 0
+  ((time_t) -1 < 0
    ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
-#endif
    : -1);
 static size_t	longest;
 static char *	progname;
@@ -223,7 +208,6 @@ static void	abbrok(const char * abbrp, const char * zone);
 static intmax_t	delta(struct tm * newp, struct tm * oldp) ATTRIBUTE_PURE;
 static void	dumptime(const struct tm * tmp);
 static time_t	hunt(char * name, time_t lot, time_t	hit);
-static void	checkabsolutes(void);
 static void	show(char * zone, time_t t, int v);
 static const char *	tformat(void);
 static time_t	yeartot(intmax_t y) ATTRIBUTE_PURE;
@@ -383,7 +367,6 @@ main(int argc, char *argv[])
 				exit(EXIT_FAILURE);
 			}
 		}
-		checkabsolutes();
 		if (cutarg != NULL || cuttimes == NULL) {
 			cutlotime = yeartot(cutloyear);
 			cuthitime = yeartot(cuthiyear);
@@ -504,17 +487,6 @@ main(int argc, char *argv[])
 	return EXIT_FAILURE;
 }
 
-static void
-checkabsolutes(void)
-{
-	if (absolute_max_time < absolute_min_time) {
-		(void) fprintf(stderr,
-_("%s: use of -v on system with floating time_t other than float or double\n"),
-			       progname);
-		exit(EXIT_FAILURE);
-	}
-}
-
 static time_t
 yeartot(const intmax_t y)
 {
@@ -666,11 +638,6 @@ abbr(struct tm *tmp)
 static const char *
 tformat(void)
 {
-	if (0.5 == (time_t) 0.5) {	/* floating */
-		if (sizeof (time_t) > sizeof (double))
-			return "%Lg";
-		return "%g";
-	}
 	if (0 > (time_t) -1) {		/* signed */
 		if (sizeof (time_t) == sizeof (intmax_t))
 			return "%"PRIdMAX;
-- 
1.8.1.2



More information about the tz mailing list