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.2  2003/12/19 22:26:37  drsung
00038  * Dox written.
00039  *
00040  * Revision 1.1  2003/11/24 18:07:37  drsung
00041  * first release
00042  *
00043  *
00044  */
00045 
00046 #include <time.h>
00047 #include "ctime.h"
00048 
00049 #define __need_NULL
00050 #include <stddef.h>
00051 
00052 /*
00053  * ChkAdd evaluates to TRUE if dest = src1 + src2 has overflowed
00054  */
00055 #define ChkAdd(dest, src1, src2)   ( ((src1 >= 0L) && (src2 >= 0L) \
00056     && (dest < 0L)) || ((src1 < 0L) && (src2 < 0L) && (dest >= 0L)) )
00057 
00058 /*
00059  * ChkMul evaluates to TRUE if dest = src1 * src2 has overflowed
00060  */
00061 #define ChkMul(dest, src1, src2)   ( src1 ? (dest/src1 != src2) : 0 )
00062 
00068 static time_t _make_time_t(tm * tb, int ultflag)
00069 {
00070     long tmptm1, tmptm2, tmptm3;
00071     tm *tbtemp;
00072 
00073     /*
00074      * First, make sure tm_year is reasonably close to being in range.
00075      */
00076     if (((tmptm1 = tb->tm_year) < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1))
00077         goto err_mktime;
00078 
00079 
00080     /*
00081      * Adjust month value so it is in the range 0 - 11.  This is because
00082      * we don't know how many days are in months 12, 13, 14, etc.
00083      */
00084 
00085     if ((tb->tm_mon < 0) || (tb->tm_mon > 11)) {
00086 
00087         /*
00088          * no danger of overflow because the range check above.
00089          */
00090         tmptm1 += (tb->tm_mon / 12);
00091 
00092         if ((tb->tm_mon %= 12) < 0) {
00093             tb->tm_mon += 12;
00094             tmptm1--;
00095         }
00096 
00097         /*
00098          * Make sure year count is still in range.
00099          */
00100         if ((tmptm1 < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1))
00101             goto err_mktime;
00102     }
00103 
00104         /***** HERE: tmptm1 holds number of elapsed years *****/
00105 
00106     /*
00107      * Calculate days elapsed minus one, in the given year, to the given
00108      * month. Check for leap year and adjust if necessary.
00109      */
00110     tmptm2 = _days[tb->tm_mon];
00111     if (!(tmptm1 & 3) && (tb->tm_mon > 1))
00112         tmptm2++;
00113 
00114     /*
00115      * Calculate elapsed days since base date (midnight, 1/1/70, UTC)
00116      *
00117      *
00118      * 365 days for each elapsed year since 1970, plus one more day for
00119      * each elapsed leap year. no danger of overflow because of the range
00120      * check (above) on tmptm1.
00121      */
00122     tmptm3 = (tmptm1 - _BASE_YEAR) * 365L + ((tmptm1 - 1L) >> 2)
00123         - _LEAP_YEAR_ADJUST;
00124 
00125     /*
00126      * elapsed days to current month (still no possible overflow)
00127      */
00128     tmptm3 += tmptm2;
00129 
00130     /*
00131      * elapsed days to current date. overflow is now possible.
00132      */
00133     tmptm1 = tmptm3 + (tmptm2 = (long) (tb->tm_mday));
00134     if (ChkAdd(tmptm1, tmptm3, tmptm2))
00135         goto err_mktime;
00136 
00137         /***** HERE: tmptm1 holds number of elapsed days *****/
00138 
00139     /*
00140      * Calculate elapsed hours since base date
00141      */
00142     tmptm2 = tmptm1 * 24L;
00143     if (ChkMul(tmptm2, tmptm1, 24L))
00144         goto err_mktime;
00145 
00146     tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_hour);
00147     if (ChkAdd(tmptm1, tmptm2, tmptm3))
00148         goto err_mktime;
00149 
00150         /***** HERE: tmptm1 holds number of elapsed hours *****/
00151 
00152     /*
00153      * Calculate elapsed minutes since base date
00154      */
00155 
00156     tmptm2 = tmptm1 * 60L;
00157     if (ChkMul(tmptm2, tmptm1, 60L))
00158         goto err_mktime;
00159 
00160     tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_min);
00161     if (ChkAdd(tmptm1, tmptm2, tmptm3))
00162         goto err_mktime;
00163 
00164         /***** HERE: tmptm1 holds number of elapsed minutes *****/
00165 
00166     /*
00167      * Calculate elapsed seconds since base date
00168      */
00169 
00170     tmptm2 = tmptm1 * 60L;
00171     if (ChkMul(tmptm2, tmptm1, 60L))
00172         goto err_mktime;
00173 
00174     tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_sec);
00175     if (ChkAdd(tmptm1, tmptm2, tmptm3))
00176         goto err_mktime;
00177 
00178         /***** HERE: tmptm1 holds number of elapsed seconds *****/
00179 
00180     if (ultflag) {
00181 
00182         /*
00183          * Adjust for timezone. No need to check for overflow since
00184          * localtime() will check its arg value
00185          */
00186 
00187         tmptm1 += _timezone;
00188 
00189         /*
00190          * Convert this second count back into a time block structure.
00191          * If localtime returns NULL, return an error.
00192          */
00193         if ((tbtemp = localtime(&tmptm1)) == NULL)
00194             goto err_mktime;
00195 
00196         /*
00197          * Now must compensate for DST. The ANSI rules are to use the
00198          * passed-in tm_isdst flag if it is non-negative. Otherwise,
00199          * compute if DST applies. Recall that tbtemp has the time without
00200          * DST compensation, but has set tm_isdst correctly.
00201          */
00202         if ((tb->tm_isdst > 0) || ((tb->tm_isdst < 0) && (tbtemp->tm_isdst > 0))) {
00203             tmptm1 += _dstbias;
00204             tbtemp = localtime(&tmptm1);        /* reconvert, can't get NULL */
00205         }
00206 
00207     } else {
00208         if ((tbtemp = gmtime(&tmptm1)) == NULL)
00209             goto err_mktime;
00210     }
00211 
00212         /***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/
00213         /*****       for local time if requested                      *****/
00214 
00215     *tb = *tbtemp;
00216     return (time_t) tmptm1;
00217 
00218   err_mktime:
00219     /*
00220      * All errors come to here
00221      */
00222     return (time_t) (-1);
00223 }
00224 
00267 time_t mktime(tm * timeptr)
00268 {
00269     return (_make_time_t(timeptr, 1));
00270 }
00271 
00272 time_t _mkgmtime(tm * timeptr)
00273 {
00274     return (_make_time_t(timeptr, 0));
00275 }
00276 

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