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.3 2008/08/11 06:59:41 haraldkipp 00038 * BSD types replaced by stdint types (feature request #1282721). 00039 * 00040 * Revision 1.2 2003/12/19 22:26:38 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 typedef struct { 00055 int yr; /* year of interest */ 00056 int yd; /* day of year */ 00057 long ms; /* milli-seconds in the day */ 00058 } transitiondate; 00059 00060 /* 00061 * DST start and end structs. 00062 */ 00063 static transitiondate dststart = { -1, 0, 0L }; 00064 static transitiondate dstend = { -1, 0, 0L }; 00065 int _daylight = 1; /* daylight saving default enabled */ 00066 long _dstbias = -1 * 60L * 60L; /* bias for daylight saving in seconds */ 00067 long _timezone = 5L * 60L * 60L; /* default time zone is EST = -05:00:00 */ 00068 00069 /* 00070 * The macro below is valid for years between 1901 and 2099, which easily 00071 * includes all years representable by the current implementation of time_t. 00072 */ 00073 #define IS_LEAP_YEAR(year) ( (year & 3) == 0 ) 00074 #define DAY_MILLISEC (24L * 60L * 60L * 1000L) 00075 00076 00077 static void cvtdate(int trantype, 00078 int datetype, int year, int month, int week, int dayofweek, int date, int hour, int min, int sec, int msec) 00079 { 00080 int yearday; 00081 int monthdow; 00082 00083 if (datetype == 1) { 00084 00085 /* 00086 * Transition day specified in day-in-month format. 00087 */ 00088 00089 /* 00090 * Figure the year-day of the start of the month. 00091 */ 00092 yearday = 1 + (IS_LEAP_YEAR(year) ? _lpdays[month - 1] : _days[month - 1]); 00093 00094 /* 00095 * Figure the day of the week of the start of the month. 00096 */ 00097 monthdow = (yearday + ((year - 70) * 365) + ((year - 1) >> 2) - _LEAP_YEAR_ADJUST + _BASE_DOW) % 7; 00098 00099 /* 00100 * Figure the year-day of the transition date 00101 */ 00102 if (monthdow <= dayofweek) 00103 yearday += (dayofweek - monthdow) + (week - 1) * 7; 00104 else 00105 yearday += (dayofweek - monthdow) + week * 7; 00106 00107 /* 00108 * May have to adjust the calculation above if week == 5 (meaning 00109 * the last instance of the day in the month). Check if year falls 00110 * beyond after month and adjust accordingly. 00111 */ 00112 if ((week == 5) && (yearday > (IS_LEAP_YEAR(year) ? _lpdays[month] : _days[month]))) { 00113 yearday -= 7; 00114 } 00115 } else { 00116 /* 00117 * Transition day specified as an absolute day 00118 */ 00119 yearday = IS_LEAP_YEAR(year) ? _lpdays[month - 1] : _days[month - 1]; 00120 00121 yearday += date; 00122 } 00123 00124 if (trantype == 1) { 00125 /* 00126 * Converted date was for the start of DST 00127 */ 00128 dststart.yd = yearday; 00129 dststart.ms = (long) msec + (1000L * (sec + 60L * (min + 60L * hour))); 00130 /* 00131 * Set year field of dststart so that unnecessary calls to 00132 * cvtdate() may be avoided. 00133 */ 00134 dststart.yr = year; 00135 } else { 00136 /* 00137 * Converted date was for the end of DST 00138 */ 00139 dstend.yd = yearday; 00140 dstend.ms = (long) msec + (1000L * (sec + 60L * (min + 60L * hour))); 00141 /* 00142 * The converted date is still a DST date. Must convert to a 00143 * standard (local) date while being careful the millisecond field 00144 * does not overflow or underflow. 00145 */ 00146 if ((dstend.ms += (_dstbias * 1000L)) < 0) { 00147 dstend.ms += DAY_MILLISEC; 00148 dstend.yd--; 00149 } else if (dstend.ms >= DAY_MILLISEC) { 00150 dstend.ms -= DAY_MILLISEC; 00151 dstend.yd++; 00152 } 00153 00154 /* 00155 * Set year field of dstend so that unnecessary calls to cvtdate() 00156 * may be avoided. 00157 */ 00158 dstend.yr = year; 00159 } 00160 00161 return; 00162 } 00163 00164 00165 int _isindst(tm * tb) 00166 { 00167 long ms; 00168 if (_daylight == 0) 00169 return 0; 00170 00171 /* 00172 * Compute (recompute) the transition dates for daylight saving time 00173 * if necessary.The yr (year) fields of dststart and dstend is 00174 * compared to the year of interest to determine necessity. 00175 */ 00176 if ((tb->tm_year != dststart.yr) || (tb->tm_year != dstend.yr)) { 00177 00178 cvtdate(1, 1, tb->tm_year, 3, /* March */ 00179 5, /* last... */ 00180 0, /* ...Sunday */ 00181 0, 2, /* 02:00 (2 AM) */ 00182 0, 0, 0); 00183 00184 cvtdate(0, 1, tb->tm_year, 10, /* October */ 00185 5, /* last... */ 00186 0, /* ...Sunday */ 00187 0, 2, /* 02:00 (2 AM) */ 00188 0, 0, 0); 00189 } 00190 00191 /* 00192 * Handle simple cases first. 00193 */ 00194 if (dststart.yd < dstend.yd) { 00195 /* 00196 * Northern hemisphere ordering 00197 */ 00198 if ((tb->tm_yday < dststart.yd) || (tb->tm_yday > dstend.yd)) 00199 return 0; 00200 if ((tb->tm_yday > dststart.yd) && (tb->tm_yday < dstend.yd)) 00201 return 1; 00202 } else { 00203 /* 00204 * Southern hemisphere ordering 00205 */ 00206 if ((tb->tm_yday < dstend.yd) || (tb->tm_yday > dststart.yd)) 00207 return 1; 00208 if ((tb->tm_yday > dstend.yd) && (tb->tm_yday < dststart.yd)) 00209 return 0; 00210 } 00211 00212 ms = 1000L * (tb->tm_sec + 60L * tb->tm_min + 3600L * tb->tm_hour); 00213 00214 if (tb->tm_yday == dststart.yd) { 00215 if (ms >= dststart.ms) 00216 return 1; 00217 else 00218 return 0; 00219 } else { 00220 if (ms < dstend.ms) 00221 return 1; 00222 else 00223 return 0; 00224 } 00225 00226 }