[PATCH] Remove attempt to support floating-point time_t.
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
participants (1)
-
Paul Eggert