Nut/OS  4.10.3
API Reference
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$
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 }