mktime.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2003 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  * Portions of the following functions are derived from material which is 
00033  * Copyright (c) 1985 by Microsoft Corporation.  All rights are reserved.
00034  */
00035 /*
00036  * $Log: mktime.c,v $
00037  * Revision 1.3  2008/08/11 06:59:40  haraldkipp
00038  * BSD types replaced by stdint types (feature request #1282721).
00039  *
00040  * Revision 1.2  2003/12/19 22:26:37  drsung
00041  * Dox written.
00042  *
00043  * Revision 1.1  2003/11/24 18:07:37  drsung
00044  * first release
00045  *
00046  *
00047  */
00048 
00049 #include <stdint.h>
00050 
00051 #include <time.h>
00052 #include "ctime.h"
00053 
00054 #define __need_NULL
00055 #include <stddef.h>
00056 
00057 /*
00058  * ChkAdd evaluates to TRUE if dest = src1 + src2 has overflowed
00059  */
00060 #define ChkAdd(dest, src1, src2)   ( ((src1 >= 0L) && (src2 >= 0L) \
00061     && (dest < 0L)) || ((src1 < 0L) && (src2 < 0L) && (dest >= 0L)) )
00062 
00063 /*
00064  * ChkMul evaluates to TRUE if dest = src1 * src2 has overflowed
00065  */
00066 #define ChkMul(dest, src1, src2)   ( src1 ? (dest/src1 != src2) : 0 )
00067 
00073 static time_t _make_time_t(tm * tb, int ultflag)
00074 {
00075     long tmptm1, tmptm2, tmptm3;
00076     tm *tbtemp;
00077 
00078     /*
00079      * First, make sure tm_year is reasonably close to being in range.
00080      */
00081     if (((tmptm1 = tb->tm_year) < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1))
00082         goto err_mktime;
00083 
00084 
00085     /*
00086      * Adjust month value so it is in the range 0 - 11.  This is because
00087      * we don't know how many days are in months 12, 13, 14, etc.
00088      */
00089 
00090     if ((tb->tm_mon < 0) || (tb->tm_mon > 11)) {
00091 
00092         /*
00093          * no danger of overflow because the range check above.
00094          */
00095         tmptm1 += (tb->tm_mon / 12);
00096 
00097         if ((tb->tm_mon %= 12) < 0) {
00098             tb->tm_mon += 12;
00099             tmptm1--;
00100         }
00101 
00102         /*
00103          * Make sure year count is still in range.
00104          */
00105         if ((tmptm1 < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1))
00106             goto err_mktime;
00107     }
00108 
00109         /***** HERE: tmptm1 holds number of elapsed years *****/
00110 
00111     /*
00112      * Calculate days elapsed minus one, in the given year, to the given
00113      * month. Check for leap year and adjust if necessary.
00114      */
00115     tmptm2 = _days[tb->tm_mon];
00116     if (!(tmptm1 & 3) && (tb->tm_mon > 1))
00117         tmptm2++;
00118 
00119     /*
00120      * Calculate elapsed days since base date (midnight, 1/1/70, UTC)
00121      *
00122      *
00123      * 365 days for each elapsed year since 1970, plus one more day for
00124      * each elapsed leap year. no danger of overflow because of the range
00125      * check (above) on tmptm1.
00126      */
00127     tmptm3 = (tmptm1 - _BASE_YEAR) * 365L + ((tmptm1 - 1L) >> 2)
00128         - _LEAP_YEAR_ADJUST;
00129 
00130     /*
00131      * elapsed days to current month (still no possible overflow)
00132      */
00133     tmptm3 += tmptm2;
00134 
00135     /*
00136      * elapsed days to current date. overflow is now possible.
00137      */
00138     tmptm1 = tmptm3 + (tmptm2 = (long) (tb->tm_mday));
00139     if (ChkAdd(tmptm1, tmptm3, tmptm2))
00140         goto err_mktime;
00141 
00142         /***** HERE: tmptm1 holds number of elapsed days *****/
00143 
00144     /*
00145      * Calculate elapsed hours since base date
00146      */
00147     tmptm2 = tmptm1 * 24L;
00148     if (ChkMul(tmptm2, tmptm1, 24L))
00149         goto err_mktime;
00150 
00151     tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_hour);
00152     if (ChkAdd(tmptm1, tmptm2, tmptm3))
00153         goto err_mktime;
00154 
00155         /***** HERE: tmptm1 holds number of elapsed hours *****/
00156 
00157     /*
00158      * Calculate elapsed minutes since base date
00159      */
00160 
00161     tmptm2 = tmptm1 * 60L;
00162     if (ChkMul(tmptm2, tmptm1, 60L))
00163         goto err_mktime;
00164 
00165     tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_min);
00166     if (ChkAdd(tmptm1, tmptm2, tmptm3))
00167         goto err_mktime;
00168 
00169         /***** HERE: tmptm1 holds number of elapsed minutes *****/
00170 
00171     /*
00172      * Calculate elapsed seconds since base date
00173      */
00174 
00175     tmptm2 = tmptm1 * 60L;
00176     if (ChkMul(tmptm2, tmptm1, 60L))
00177         goto err_mktime;
00178 
00179     tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_sec);
00180     if (ChkAdd(tmptm1, tmptm2, tmptm3))
00181         goto err_mktime;
00182 
00183         /***** HERE: tmptm1 holds number of elapsed seconds *****/
00184 
00185     if (ultflag) {
00186 
00187         /*
00188          * Adjust for timezone. No need to check for overflow since
00189          * localtime() will check its arg value
00190          */
00191 
00192         tmptm1 += _timezone;
00193 
00194         /*
00195          * Convert this second count back into a time block structure.
00196          * If localtime returns NULL, return an error.
00197          */
00198         if ((tbtemp = localtime(&tmptm1)) == NULL)
00199             goto err_mktime;
00200 
00201         /*
00202          * Now must compensate for DST. The ANSI rules are to use the
00203          * passed-in tm_isdst flag if it is non-negative. Otherwise,
00204          * compute if DST applies. Recall that tbtemp has the time without
00205          * DST compensation, but has set tm_isdst correctly.
00206          */
00207         if ((tb->tm_isdst > 0) || ((tb->tm_isdst < 0) && (tbtemp->tm_isdst > 0))) {
00208             tmptm1 += _dstbias;
00209             tbtemp = localtime(&tmptm1);        /* reconvert, can't get NULL */
00210         }
00211 
00212     } else {
00213         if ((tbtemp = gmtime(&tmptm1)) == NULL)
00214             goto err_mktime;
00215     }
00216 
00217         /***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/
00218         /*****       for local time if requested                      *****/
00219 
00220     *tb = *tbtemp;
00221     return (time_t) tmptm1;
00222 
00223   err_mktime:
00224     /*
00225      * All errors come to here
00226      */
00227     return (time_t) (-1);
00228 }
00229 
00272 time_t mktime(tm * timeptr)
00273 {
00274     return (_make_time_t(timeptr, 1));
00275 }
00276 
00277 time_t _mkgmtime(tm * timeptr)
00278 {
00279     return (_make_time_t(timeptr, 0));
00280 }
00281 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/