1 /* mkgmtime.c - make time corresponding to a GMT timeval struct
2  *
3  * Copyright (c) 1994-2008 Carnegie Mellon University.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. The name "Carnegie Mellon University" must not be used to
18  *    endorse or promote products derived from this software without
19  *    prior written permission. For permission or any legal
20  *    details, please contact
21  *      Carnegie Mellon University
22  *      Center for Technology Transfer and Enterprise Creation
23  *      4615 Forbes Avenue
24  *      Suite 302
25  *      Pittsburgh, PA  15213
26  *      (412) 268-7393, fax: (412) 268-7395
27  *      innovation@andrew.cmu.edu
28  *
29  * 4. Redistributions of any form whatsoever must retain the following
30  *    acknowledgment:
31  *    "This product includes software developed by Computing Services
32  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33  *
34  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41  */
42 /*
43  * Copyright (c) 1987, 1989, 1993
44  *      The Regents of the University of California.  All rights reserved.
45  *
46  * This code is derived from software contributed to Berkeley by
47  * Arthur David Olson of the National Cancer Institute.
48  *
49  * Redistribution and use in source and binary forms, with or without
50  * modification, are permitted provided that the following conditions
51  * are met:
52  * 1. Redistributions of source code must retain the above copyright
53  *    notice, this list of conditions and the following disclaimer.
54  * 2. Redistributions in binary form must reproduce the above copyright
55  *    notice, this list of conditions and the following disclaimer in the
56  *    documentation and/or other materials provided with the distribution.
57  * 3. All advertising materials mentioning features or use of this software
58  *    must display the following acknowledgement:
59  *      This product includes software developed by the University of
60  *      California, Berkeley and its contributors.
61  * 4. Neither the name of the University nor the names of its contributors
62  *    may be used to endorse or promote products derived from this software
63  *    without specific prior written permission.
64  *
65  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
66  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
67  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
68  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
69  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
70  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
71  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
72  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
73  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
74  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
75  * SUCH DAMAGE.
76  */
77 
78 /*
79 ** Adapted from code provided by Robert Elz, who writes:
80 **      The "best" way to do mktime I think is based on an idea of Bob
81 **      Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
82 **      It does a binary search of the time_t space.  Since time_t's are
83 **      just 32 bits, its a max of 32 iterations (even at 64 bits it
84 **      would still be very reasonable).
85 */
86 /*
87  * Fortunately, modern libc implementations on Linux, BSD and Solaris
88  * provide a timegm() function that does exactly this but more efficiently
89  * using the internal libc data structures.  We use that if configure
90  * discovered it - gnb@fastmail.fm
91  */
92 
93 #include <config.h>
94 
95 #if HAVE_TIMEGM
96 
mkgmtime(struct tm * const tmp)97 EXPORTED time_t mkgmtime(struct tm * const tmp)
98 {
99     return timegm(tmp);
100 }
101 
102 #else
103 
104 #ifndef WRONG
105 #define WRONG   (-1)
106 #endif /* !defined WRONG */
107 
108 static int
tmcomp(atmp,btmp)109 tmcomp(atmp, btmp)
110 register const struct tm * const atmp;
111 register const struct tm * const btmp;
112 {
113         register int    result;
114 
115         if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
116                 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
117                 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
118                 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
119                 (result = (atmp->tm_min - btmp->tm_min)) == 0)
120                         result = atmp->tm_sec - btmp->tm_sec;
121         return result;
122 }
123 
124 time_t
mkgmtime(tmp)125 mkgmtime(tmp)
126 struct tm * const       tmp;
127 {
128         register int                    dir;
129         register int                    bits;
130         register int                    saved_seconds;
131         time_t                          t;
132         struct tm                       yourtm, *mytm;
133 
134         yourtm = *tmp;
135         saved_seconds = yourtm.tm_sec;
136         yourtm.tm_sec = 0;
137         /*
138         ** Calculate the number of magnitude bits in a time_t
139         ** (this works regardless of whether time_t is
140         ** signed or unsigned, though lint complains if unsigned).
141         */
142         for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
143                 ;
144         /*
145         ** If time_t is signed, then 0 is the median value,
146         ** if time_t is unsigned, then 1 << bits is median.
147         */
148         t = (t < 0) ? 0 : ((time_t) 1 << bits);
149 
150         /* Some gmtime() implementations are broken and will return
151          * NULL for time_ts larger than 40 bits even on 64-bit platforms
152          * so we'll just cap it at 40 bits */
153         if(bits > 40) bits = 40;
154 
155         for ( ; ; ) {
156                 mytm = gmtime(&t);
157 
158                 if(!mytm) return WRONG;
159 
160                 dir = tmcomp(mytm, &yourtm);
161                 if (dir != 0) {
162                         if (bits-- < 0)
163                                 return WRONG;
164                         if (bits < 0)
165                                 --t;
166                         else if (dir > 0)
167                                 t -= (time_t) 1 << bits;
168                         else    t += (time_t) 1 << bits;
169                         continue;
170                 }
171                 break;
172         }
173         t += saved_seconds;
174         return t;
175 }
176 
177 #endif /* HAVE_TIMEGM */
178