1*0a6a1f1dSLionel Sambuc /* $NetBSD: difftime.c,v 1.16 2015/08/13 11:21:18 christos Exp $ */ 22fe8fb19SBen Gras 32fe8fb19SBen Gras /* 42fe8fb19SBen Gras ** This file is in the public domain, so clarified as of 52fe8fb19SBen Gras ** 1996-06-05 by Arthur David Olson. 62fe8fb19SBen Gras */ 72fe8fb19SBen Gras 82fe8fb19SBen Gras #include <sys/cdefs.h> 92fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint) 102fe8fb19SBen Gras #if 0 112fe8fb19SBen Gras static char elsieid[] = "@(#)difftime.c 8.1"; 122fe8fb19SBen Gras #else 13*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: difftime.c,v 1.16 2015/08/13 11:21:18 christos Exp $"); 142fe8fb19SBen Gras #endif 152fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */ 162fe8fb19SBen Gras 172fe8fb19SBen Gras /*LINTLIBRARY*/ 182fe8fb19SBen Gras 1984d9c625SLionel Sambuc #include "private.h" /* for time_t and TYPE_SIGNED */ 202fe8fb19SBen Gras 21*0a6a1f1dSLionel Sambuc /* Return -X as a double. Using this avoids casting to 'double'. */ 22*0a6a1f1dSLionel Sambuc static double dminus(double x)23*0a6a1f1dSLionel Sambucdminus(double x) 24*0a6a1f1dSLionel Sambuc { 25*0a6a1f1dSLionel Sambuc return -x; 26*0a6a1f1dSLionel Sambuc } 27*0a6a1f1dSLionel Sambuc 2884d9c625SLionel Sambuc double ATTRIBUTE_CONST difftime(time_t time1,time_t time0)29*0a6a1f1dSLionel Sambucdifftime(time_t time1, time_t time0) 302fe8fb19SBen Gras { 312fe8fb19SBen Gras /* 32*0a6a1f1dSLionel Sambuc ** If double is large enough, simply convert and subtract 332fe8fb19SBen Gras ** (assuming that the larger type has more precision). 342fe8fb19SBen Gras */ 35*0a6a1f1dSLionel Sambuc if (sizeof (time_t) < sizeof (double)) { 36*0a6a1f1dSLionel Sambuc double t1 = time1, t0 = time0; 37*0a6a1f1dSLionel Sambuc return t1 - t0; 38*0a6a1f1dSLionel Sambuc } 39*0a6a1f1dSLionel Sambuc 402fe8fb19SBen Gras /* 412fe8fb19SBen Gras ** The difference of two unsigned values can't overflow 422fe8fb19SBen Gras ** if the minuend is greater than or equal to the subtrahend. 432fe8fb19SBen Gras */ 44*0a6a1f1dSLionel Sambuc if (!TYPE_SIGNED(time_t)) 45*0a6a1f1dSLionel Sambuc return time0 <= time1 ? time1 - time0 : dminus(time0 - time1); 46*0a6a1f1dSLionel Sambuc 47*0a6a1f1dSLionel Sambuc /* Use uintmax_t if wide enough. */ 48*0a6a1f1dSLionel Sambuc if (sizeof (time_t) <= sizeof (uintmax_t)) { 49*0a6a1f1dSLionel Sambuc uintmax_t t1 = time1, t0 = time0; 50*0a6a1f1dSLionel Sambuc return time0 <= time1 ? t1 - t0 : dminus(t0 - t1); 512fe8fb19SBen Gras } 52*0a6a1f1dSLionel Sambuc 532fe8fb19SBen Gras /* 542fe8fb19SBen Gras ** Handle cases where both time1 and time0 have the same sign 552fe8fb19SBen Gras ** (meaning that their difference cannot overflow). 562fe8fb19SBen Gras */ 572fe8fb19SBen Gras if ((time1 < 0) == (time0 < 0)) 582fe8fb19SBen Gras return time1 - time0; 59*0a6a1f1dSLionel Sambuc 602fe8fb19SBen Gras /* 61*0a6a1f1dSLionel Sambuc ** The values have opposite signs and uintmax_t is too narrow. 6284d9c625SLionel Sambuc ** This suffers from double rounding; attempt to lessen that 6384d9c625SLionel Sambuc ** by using long double temporaries. 642fe8fb19SBen Gras */ 65*0a6a1f1dSLionel Sambuc { 66*0a6a1f1dSLionel Sambuc long double t1 = time1, t0 = time0; 67*0a6a1f1dSLionel Sambuc return t1 - t0; 68*0a6a1f1dSLionel Sambuc } 692fe8fb19SBen Gras } 70