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

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