xref: /minix3/lib/libc/time/difftime.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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 Sambuc dminus(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 Sambuc difftime(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