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$ 00037 * Revision 1.6 2009/01/17 15:37:52 haraldkipp 00038 * Added some NUTASSERT macros to check function parameters. 00039 * 00040 * Revision 1.5 2008/08/11 06:59:40 haraldkipp 00041 * BSD types replaced by stdint types (feature request #1282721). 00042 * 00043 * Revision 1.4 2004/10/14 16:43:00 drsung 00044 * Fixed compiler warning "comparison between signed and unsigned" 00045 * 00046 * Revision 1.3 2003/12/19 22:26:37 drsung 00047 * Dox written. 00048 * 00049 * Revision 1.2 2003/11/26 11:14:32 haraldkipp 00050 * Portability issues 00051 * 00052 * Revision 1.1 2003/11/24 18:07:37 drsung 00053 * first release 00054 * 00055 * 00056 */ 00057 00058 #include <stdint.h> 00059 00060 #include <time.h> 00061 #include "ctime.h" 00062 #include <sys/nutdebug.h> 00063 00064 #define __need_NULL 00065 #include <stddef.h> 00066 00067 #define LONG_MAX 2147483647L 00068 00084 int localtime_r(CONST time_t * timer, tm * ptm) 00085 { 00086 long ltime; 00087 00088 NUTASSERT(timer != NULL); 00089 if ((*timer > (time_t)(3 * _DAY_SEC)) && (*timer < (time_t)(LONG_MAX - 3 * _DAY_SEC))) { 00090 /* 00091 * The date does not fall within the first three, or last 00092 * three, representable days of the Epoch. Therefore, there 00093 * is no possibility of overflowing or underflowing the 00094 * time_t representation as we compensate for timezone and 00095 * Daylight Savings Time. 00096 */ 00097 00098 ltime = (long) *timer - _timezone; 00099 gmtime_r((time_t *) & ltime, ptm); 00100 00101 /* 00102 * Check and adjust for Daylight Saving Time. 00103 */ 00104 if (_daylight && _isindst(ptm)) { 00105 ltime -= _dstbias; 00106 gmtime_r((time_t *) & ltime, ptm); 00107 ptm->tm_isdst = 1; 00108 } 00109 } else { 00110 gmtime_r(timer, ptm); 00111 00112 /* 00113 * The date falls with the first three, or last three days 00114 * of the Epoch. It is possible the time_t representation 00115 * would overflow or underflow while compensating for 00116 * timezone and Daylight Savings Time. Therefore, make the 00117 * timezone and Daylight Savings Time adjustments directly 00118 * in the tm structure. The beginning of the Epoch is 00119 * 00:00:00, 01-01-70 (UCT) and the last representable second 00120 * in the Epoch is 03:14:07, 01-19-2038 (UCT). This will be 00121 * used in the calculations below. 00122 * 00123 * First, adjust for the timezone. 00124 */ 00125 if (_isindst(ptm)) 00126 ltime = (long) ptm->tm_sec - (_timezone + _dstbias); 00127 else 00128 ltime = (long) ptm->tm_sec - _timezone; 00129 ptm->tm_sec = (int) (ltime % 60); 00130 if (ptm->tm_sec < 0) { 00131 ptm->tm_sec += 60; 00132 ltime -= 60; 00133 } 00134 00135 ltime = (long) ptm->tm_min + ltime / 60; 00136 ptm->tm_min = (int) (ltime % 60); 00137 if (ptm->tm_min < 0) { 00138 ptm->tm_min += 60; 00139 ltime -= 60; 00140 } 00141 00142 ltime = (long) ptm->tm_hour + ltime / 60; 00143 ptm->tm_hour = (int) (ltime % 24); 00144 if (ptm->tm_hour < 0) { 00145 ptm->tm_hour += 24; 00146 ltime -= 24; 00147 } 00148 00149 ltime /= 24; 00150 00151 if (ltime > 0L) { 00152 /* 00153 * There is no possibility of overflowing the tm_mday 00154 * and tm_yday fields since the date can be no later 00155 * than January 19. 00156 */ 00157 ptm->tm_wday = (ptm->tm_wday + ltime) % 7; 00158 ptm->tm_mday += ltime; 00159 ptm->tm_yday += ltime; 00160 } else if (ltime < 0L) { 00161 /* 00162 * It is possible to underflow the tm_mday and tm_yday 00163 * fields. If this happens, then adjusted date must 00164 * lie in December 1969. 00165 */ 00166 ptm->tm_wday = (ptm->tm_wday + 7 + ltime) % 7; 00167 if ((ptm->tm_mday += ltime) <= 0) { 00168 ptm->tm_mday += 31; 00169 ptm->tm_yday = 364; 00170 ptm->tm_mon = 11; 00171 ptm->tm_year--; 00172 } else { 00173 ptm->tm_yday += ltime; 00174 } 00175 } 00176 00177 00178 } 00179 return 0; 00180 } 00181 00182 00203 /* 00204 Note: This function is *not* thread safe, because it uses a static variable 00205 to store the calculated values. To be safe, you must surround the call to localtime 00206 _and_ the usage of the returned pointer with NutEnterCritical() and NutExitCritical()! 00207 Provided for compatibility to std c lib. 00208 */ 00209 tm *localtime(CONST time_t * timer) 00210 { 00211 if (localtime_r(timer, &_tb)) 00212 return NULL; 00213 else 00214 return &_tb; 00215 } 00216