1*ace5b9b5Schristos /* $NetBSD: difftime.c,v 1.24 2024/01/20 14:52:49 christos Exp $ */ 2b2b04f7eSchristos 3b2b04f7eSchristos /* Return the difference between two timestamps. */ 49b9f8829Sjtc 59b9f8829Sjtc /* 69b9f8829Sjtc ** This file is in the public domain, so clarified as of 786162a51Smlelstv ** 1996-06-05 by Arthur David Olson. 89b9f8829Sjtc */ 9ac908354Sjtc 103ad08ca2Schristos #include <sys/cdefs.h> 11f9b799b6Smsaitoh #if defined(LIBC_SCCS) && !defined(lint) 123ad08ca2Schristos #if 0 1386162a51Smlelstv static char elsieid[] = "@(#)difftime.c 8.1"; 143ad08ca2Schristos #else 15*ace5b9b5Schristos __RCSID("$NetBSD: difftime.c,v 1.24 2024/01/20 14:52:49 christos Exp $"); 163ad08ca2Schristos #endif 17f9b799b6Smsaitoh #endif /* LIBC_SCCS and not lint */ 18f9b799b6Smsaitoh 191fac1c17Sjtc /*LINTLIBRARY*/ 201fac1c17Sjtc 2133d9f9e0Schristos #include "private.h" /* for time_t and TYPE_SIGNED */ 221fac1c17Sjtc 23d856f74aSchristos /* Return -X as a double. Using this avoids casting to 'double'. */ 24d856f74aSchristos static double dminus(double x)25d856f74aSchristosdminus(double x) 26d856f74aSchristos { 27d856f74aSchristos return -x; 28d856f74aSchristos } 29d856f74aSchristos 305f2f4c60Schristos double difftime(time_t time1,time_t time0)31d856f74aSchristosdifftime(time_t time1, time_t time0) 321fac1c17Sjtc { 3386162a51Smlelstv /* 34d856f74aSchristos ** If double is large enough, simply convert and subtract 3586162a51Smlelstv ** (assuming that the larger type has more precision). 3686162a51Smlelstv */ 37d472a915Schristos /*CONSTCOND*/ 38d856f74aSchristos if (sizeof(time_t) < sizeof(double)) { 39d856f74aSchristos double t1 = time1, t0 = time0; 40d856f74aSchristos return t1 - t0; 41d856f74aSchristos } 42d856f74aSchristos 431fac1c17Sjtc /* 4486162a51Smlelstv ** The difference of two unsigned values can't overflow 4586162a51Smlelstv ** if the minuend is greater than or equal to the subtrahend. 461fac1c17Sjtc */ 47d856f74aSchristos if (!TYPE_SIGNED(time_t)) 48*ace5b9b5Schristos /*NOTREACHED*/ 491ef6fb3dSchristos return time0 <= time1 ? time1 - time0 : 501ef6fb3dSchristos dminus((double)(time0 - time1)); 51d856f74aSchristos 52d856f74aSchristos /* Use uintmax_t if wide enough. */ 53d472a915Schristos /*CONSTCOND*/ 54d856f74aSchristos if (sizeof(time_t) <= sizeof(uintmax_t)) { 55d856f74aSchristos uintmax_t t1 = time1, t0 = time0; 561ef6fb3dSchristos return time0 <= time1 ? t1 - t0 : dminus((double)(t0 - t1)); 5786162a51Smlelstv } 58d856f74aSchristos 591fac1c17Sjtc /* 6086162a51Smlelstv ** Handle cases where both time1 and time0 have the same sign 6186162a51Smlelstv ** (meaning that their difference cannot overflow). 621fac1c17Sjtc */ 6386162a51Smlelstv if ((time1 < 0) == (time0 < 0)) 6486162a51Smlelstv return time1 - time0; 65d856f74aSchristos 661fac1c17Sjtc /* 67d856f74aSchristos ** The values have opposite signs and uintmax_t is too narrow. 68a37624b5Schristos ** This suffers from double rounding; attempt to lessen that 69a37624b5Schristos ** by using long double temporaries. 701fac1c17Sjtc */ 71d856f74aSchristos { 72d856f74aSchristos long double t1 = time1, t0 = time0; 73d856f74aSchristos return t1 - t0; 74d856f74aSchristos } 751fac1c17Sjtc } 76