154359Sroberto/* 254359Sroberto * Copyright (c) 1987, 1989 Regents of the University of California. 354359Sroberto * All rights reserved. 454359Sroberto * 554359Sroberto * This code is derived from software contributed to Berkeley by 654359Sroberto * Arthur David Olson of the National Cancer Institute. 754359Sroberto * 854359Sroberto * Redistribution and use in source and binary forms, with or without 954359Sroberto * modification, are permitted provided that the following conditions 1054359Sroberto * are met: 1154359Sroberto * 1. Redistributions of source code must retain the above copyright 1254359Sroberto * notice, this list of conditions and the following disclaimer. 1354359Sroberto * 2. Redistributions in binary form must reproduce the above copyright 1454359Sroberto * notice, this list of conditions and the following disclaimer in the 1554359Sroberto * documentation and/or other materials provided with the distribution. 1654359Sroberto * 3. All advertising materials mentioning features or use of this software 1754359Sroberto * must display the following acknowledgement: 1854359Sroberto * This product includes software developed by the University of 1954359Sroberto * California, Berkeley and its contributors. 2054359Sroberto * 4. Neither the name of the University nor the names of its contributors 2154359Sroberto * may be used to endorse or promote products derived from this software 2254359Sroberto * without specific prior written permission. 2354359Sroberto * 2454359Sroberto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2554359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2654359Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2754359Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2854359Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2954359Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3054359Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3154359Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3254359Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3354359Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3454359Sroberto * SUCH DAMAGE. */ 3554359Sroberto 3654359Sroberto/*static char *sccsid = "from: @(#)ctime.c 5.26 (Berkeley) 2/23/91";*/ 3754359Sroberto 3854359Sroberto/* 3954359Sroberto * This implementation of mktime is lifted straight from the NetBSD (BSD 4.4) 4054359Sroberto * version. I modified it slightly to divorce it from the internals of the 4154359Sroberto * ctime library. Thus this version can't use details of the internal 4254359Sroberto * timezone state file to figure out strange unnormalized struct tm values, 4354359Sroberto * as might result from someone doing date math on the tm struct then passing 4454359Sroberto * it to mktime. 4554359Sroberto * 4654359Sroberto * It just does as well as it can at normalizing the tm input, then does a 4754359Sroberto * binary search of the time space using the system's localtime() function. 4854359Sroberto * 4954359Sroberto * The original binary search was defective in that it didn't consider the 5054359Sroberto * setting of tm_isdst when comparing tm values, causing the search to be 5154359Sroberto * flubbed for times near the dst/standard time changeover. The original 5254359Sroberto * code seems to make up for this by grubbing through the timezone info 5354359Sroberto * whenever the binary search barfed. Since I don't have that luxury in 5454359Sroberto * portable code, I have to take care of tm_isdst in the comparison routine. 5554359Sroberto * This requires knowing how many minutes offset dst is from standard time. 5654359Sroberto * 5754359Sroberto * So, if you live somewhere in the world where dst is not 60 minutes offset, 5854359Sroberto * and your vendor doesn't supply mktime(), you'll have to edit this variable 5954359Sroberto * by hand. Sorry about that. 6054359Sroberto */ 6154359Sroberto 62290001Sglebius#include <config.h> 6382498Sroberto#include "ntp_machine.h" 6454359Sroberto 65290001Sglebius#if !defined(HAVE_MKTIME) || ( !defined(HAVE_TIMEGM) && defined(WANT_TIMEGM) ) 66106163Sroberto 67290001Sglebius#if SIZEOF_TIME_T >= 8 68290001Sglebius#error libntp supplied mktime()/timegm() do not support 64-bit time_t 69290001Sglebius#endif 70290001Sglebius 7154359Sroberto#ifndef DSTMINUTES 7254359Sroberto#define DSTMINUTES 60 7354359Sroberto#endif 7454359Sroberto 7554359Sroberto#define FALSE 0 7654359Sroberto#define TRUE 1 7754359Sroberto 7854359Sroberto/* some constants from tzfile.h */ 7954359Sroberto#define SECSPERMIN 60 8054359Sroberto#define MINSPERHOUR 60 8154359Sroberto#define HOURSPERDAY 24 8254359Sroberto#define DAYSPERWEEK 7 8354359Sroberto#define DAYSPERNYEAR 365 8454359Sroberto#define DAYSPERLYEAR 366 8554359Sroberto#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) 8654359Sroberto#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) 8754359Sroberto#define MONSPERYEAR 12 8854359Sroberto#define TM_YEAR_BASE 1900 8954359Sroberto#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) 9054359Sroberto 9154359Srobertostatic int mon_lengths[2][MONSPERYEAR] = { 9254359Sroberto { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 9354359Sroberto { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 9454359Sroberto}; 9554359Sroberto 9654359Srobertostatic int year_lengths[2] = { 9754359Sroberto DAYSPERNYEAR, DAYSPERLYEAR 9854359Sroberto}; 9954359Sroberto 10054359Sroberto/* 10154359Sroberto** Adapted from code provided by Robert Elz, who writes: 10254359Sroberto** The "best" way to do mktime I think is based on an idea of Bob 10354359Sroberto** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). 10454359Sroberto** It does a binary search of the time_t space. Since time_t's are 10554359Sroberto** just 32 bits, its a max of 32 iterations (even at 64 bits it 10654359Sroberto** would still be very reasonable). 10754359Sroberto*/ 10854359Sroberto 10954359Sroberto#ifndef WRONG 11054359Sroberto#define WRONG (-1) 11154359Sroberto#endif /* !defined WRONG */ 11254359Sroberto 11354359Srobertostatic void 11454359Srobertonormalize( 11554359Sroberto int * tensptr, 11654359Sroberto int * unitsptr, 11754359Sroberto int base 11854359Sroberto ) 11954359Sroberto{ 12054359Sroberto if (*unitsptr >= base) { 12154359Sroberto *tensptr += *unitsptr / base; 12254359Sroberto *unitsptr %= base; 12354359Sroberto } else if (*unitsptr < 0) { 12454359Sroberto --*tensptr; 12554359Sroberto *unitsptr += base; 12654359Sroberto if (*unitsptr < 0) { 12754359Sroberto *tensptr -= 1 + (-*unitsptr) / base; 12854359Sroberto *unitsptr = base - (-*unitsptr) % base; 12954359Sroberto } 13054359Sroberto } 13154359Sroberto} 13254359Sroberto 13354359Srobertostatic struct tm * 13454359Srobertomkdst( 13554359Sroberto struct tm * tmp 13654359Sroberto ) 13754359Sroberto{ 13854359Sroberto /* jds */ 13954359Sroberto static struct tm tmbuf; 14054359Sroberto 14154359Sroberto tmbuf = *tmp; 14254359Sroberto tmbuf.tm_isdst = 1; 14354359Sroberto tmbuf.tm_min += DSTMINUTES; 14454359Sroberto normalize(&tmbuf.tm_hour, &tmbuf.tm_min, MINSPERHOUR); 14554359Sroberto return &tmbuf; 14654359Sroberto} 14754359Sroberto 14854359Srobertostatic int 14954359Srobertotmcomp( 15054359Sroberto register struct tm * atmp, 15154359Sroberto register struct tm * btmp 15254359Sroberto ) 15354359Sroberto{ 15454359Sroberto register int result; 15554359Sroberto 15654359Sroberto /* compare down to the same day */ 15754359Sroberto 15854359Sroberto if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && 15954359Sroberto (result = (atmp->tm_mon - btmp->tm_mon)) == 0) 16054359Sroberto result = (atmp->tm_mday - btmp->tm_mday); 16154359Sroberto 16254359Sroberto if(result != 0) 16354359Sroberto return result; 16454359Sroberto 16554359Sroberto /* get rid of one-sided dst bias */ 16654359Sroberto 16754359Sroberto if(atmp->tm_isdst == 1 && !btmp->tm_isdst) 16854359Sroberto btmp = mkdst(btmp); 16954359Sroberto else if(btmp->tm_isdst == 1 && !atmp->tm_isdst) 17054359Sroberto atmp = mkdst(atmp); 17154359Sroberto 17254359Sroberto /* compare the rest of the way */ 17354359Sroberto 17454359Sroberto if ((result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 17554359Sroberto (result = (atmp->tm_min - btmp->tm_min)) == 0) 17654359Sroberto result = atmp->tm_sec - btmp->tm_sec; 17754359Sroberto return result; 17854359Sroberto} 17954359Sroberto 18054359Sroberto 18154359Srobertostatic time_t 18254359Srobertotime2( 18354359Sroberto struct tm * tmp, 184132451Sroberto int * okayp, 185132451Sroberto int usezn 18654359Sroberto ) 18754359Sroberto{ 18854359Sroberto register int dir; 18954359Sroberto register int bits; 19054359Sroberto register int i; 19154359Sroberto register int saved_seconds; 19254359Sroberto time_t t; 19354359Sroberto struct tm yourtm, mytm; 19454359Sroberto 19554359Sroberto *okayp = FALSE; 19654359Sroberto yourtm = *tmp; 19754359Sroberto if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) 19854359Sroberto normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); 19954359Sroberto normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); 20054359Sroberto normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); 20154359Sroberto normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); 20254359Sroberto while (yourtm.tm_mday <= 0) { 20354359Sroberto --yourtm.tm_year; 20454359Sroberto yourtm.tm_mday += 20554359Sroberto year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)]; 20654359Sroberto } 20754359Sroberto for ( ; ; ) { 20854359Sroberto i = mon_lengths[isleap(yourtm.tm_year + 20954359Sroberto TM_YEAR_BASE)][yourtm.tm_mon]; 21054359Sroberto if (yourtm.tm_mday <= i) 21154359Sroberto break; 21254359Sroberto yourtm.tm_mday -= i; 21354359Sroberto if (++yourtm.tm_mon >= MONSPERYEAR) { 21454359Sroberto yourtm.tm_mon = 0; 21554359Sroberto ++yourtm.tm_year; 21654359Sroberto } 21754359Sroberto } 21854359Sroberto saved_seconds = yourtm.tm_sec; 21954359Sroberto yourtm.tm_sec = 0; 22054359Sroberto /* 22154359Sroberto ** Calculate the number of magnitude bits in a time_t 22254359Sroberto ** (this works regardless of whether time_t is 22354359Sroberto ** signed or unsigned, though lint complains if unsigned). 22454359Sroberto */ 22554359Sroberto for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) 22654359Sroberto ; 22754359Sroberto /* 22854359Sroberto ** If time_t is signed, then 0 is the median value, 22954359Sroberto ** if time_t is unsigned, then 1 << bits is median. 23054359Sroberto */ 23154359Sroberto t = (t < 0) ? 0 : ((time_t) 1 << bits); 23254359Sroberto for ( ; ; ) { 233132451Sroberto if (usezn) 234290001Sglebius mytm = *localtime(&t); 235132451Sroberto else 236290001Sglebius mytm = *gmtime(&t); 23754359Sroberto dir = tmcomp(&mytm, &yourtm); 23854359Sroberto if (dir != 0) { 23954359Sroberto if (bits-- < 0) 24054359Sroberto return WRONG; 24154359Sroberto if (bits < 0) 24254359Sroberto --t; 24354359Sroberto else if (dir > 0) 24454359Sroberto t -= (time_t) 1 << bits; 24554359Sroberto else t += (time_t) 1 << bits; 24654359Sroberto continue; 24754359Sroberto } 24854359Sroberto if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 24954359Sroberto break; 25054359Sroberto 25154359Sroberto return WRONG; 25254359Sroberto } 25354359Sroberto t += saved_seconds; 254132451Sroberto if (usezn) 255132451Sroberto *tmp = *localtime(&t); 256132451Sroberto else 257132451Sroberto *tmp = *gmtime(&t); 25854359Sroberto *okayp = TRUE; 25954359Sroberto return t; 26054359Sroberto} 261132451Sroberto#else 262132451Srobertoint mktime_bs; 263132451Sroberto#endif /* !HAVE_MKTIME || !HAVE_TIMEGM */ 26454359Sroberto 265182007Sroberto#ifndef HAVE_MKTIME 26654359Srobertostatic time_t 26754359Srobertotime1( 26854359Sroberto struct tm * tmp 26954359Sroberto ) 27054359Sroberto{ 27154359Sroberto register time_t t; 27254359Sroberto int okay; 27354359Sroberto 27454359Sroberto if (tmp->tm_isdst > 1) 27554359Sroberto tmp->tm_isdst = 1; 276132451Sroberto t = time2(tmp, &okay, 1); 27754359Sroberto if (okay || tmp->tm_isdst < 0) 27854359Sroberto return t; 27954359Sroberto 28054359Sroberto return WRONG; 28154359Sroberto} 28254359Sroberto 28354359Srobertotime_t 28454359Srobertomktime( 28554359Sroberto struct tm * tmp 28654359Sroberto ) 28754359Sroberto{ 28854359Sroberto return time1(tmp); 28954359Sroberto} 290132451Sroberto#endif /* !HAVE_MKTIME */ 291132451Sroberto 292290001Sglebius#ifdef WANT_TIMEGM 293182007Sroberto#ifndef HAVE_TIMEGM 294132451Srobertotime_t 295132451Srobertotimegm( 296132451Sroberto struct tm * tmp 297132451Sroberto ) 298132451Sroberto{ 299132451Sroberto register time_t t; 300132451Sroberto int okay; 301132451Sroberto 302132451Sroberto tmp->tm_isdst = 0; 303132451Sroberto t = time2(tmp, &okay, 0); 304132451Sroberto if (okay || tmp->tm_isdst < 0) 305132451Sroberto return t; 306132451Sroberto 307132451Sroberto return WRONG; 308132451Sroberto} 309132451Sroberto#endif /* !HAVE_TIMEGM */ 310290001Sglebius#endif /* WANT_TIMEGM */ 311