Drizzled Public API Documentation

gmtime.cc

00001 //
00002 // time.c
00003 //
00004 // Time routines
00005 //
00006 // Copyright (C) 2002 Michael Ringgaard. All rights reserved.
00007 //
00008 // Redistribution and use in source and binary forms, with or without
00009 // modification, are permitted provided that the following conditions
00010 // are met:
00011 // 
00012 // 1. Redistributions of source code must retain the above copyright 
00013 //    notice, this list of conditions and the following disclaimer.  
00014 // 2. Redistributions in binary form must reproduce the above copyright
00015 //    notice, this list of conditions and the following disclaimer in the
00016 //    documentation and/or other materials provided with the distribution.  
00017 // 3. Neither the name of the project nor the names of its contributors
00018 //    may be used to endorse or promote products derived from this software
00019 //    without specific prior written permission. 
00020 // 
00021 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00022 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024 // ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
00025 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00027 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00028 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00031 // SUCH DAMAGE.
00032 // 
00033 
00034 #include <config.h>
00035 
00036 #include <drizzled/type/time.h>
00037 #include <drizzled/util/gmtime.h>
00038 
00039 namespace drizzled
00040 {
00041 namespace util
00042 {
00043 #define YEAR0                   1900
00044 #define EPOCH_YR                1970
00045 #define SECS_DAY                (24L * 60L * 60L)
00046 #define LEAPYEAR(year)          (!((year) % 4) && (((year) % 100) || !((year) % 400)))
00047 #define YEARSIZE(year)          (LEAPYEAR(year) ? 366 : 365)
00048 #define FIRSTSUNDAY(timp)       (((timp)->tm_yday - (timp)->tm_wday + 420) % 7)
00049 #define FIRSTDAYOF(timp)        (((timp)->tm_wday - (timp)->tm_yday + 420) % 7)
00050 
00051 #define TIME_MAX                INT64_MIN
00052 
00053 int _daylight = 0;                  // Non-zero if daylight savings time is used
00054 long _dstbias = 0;                  // Offset for Daylight Saving Time
00055 type::Time::epoch_t _timezone = 0;                 // Difference in seconds between GMT and local time
00056 const char *_tzname[2] = {"GMT", "GMT"};  // Standard/daylight savings time zone names
00057 
00058 const char *_days[] = 
00059 {
00060   "Sunday", "Monday", "Tuesday", "Wednesday",
00061   "Thursday", "Friday", "Saturday"
00062 };
00063 
00064 const char *_days_abbrev[] = 
00065 {
00066   "Sun", "Mon", "Tue", "Wed", 
00067   "Thu", "Fri", "Sat"
00068 };
00069 
00070 const char *_months[] = 
00071 {
00072   "January", "February", "March",
00073   "April", "May", "June",
00074   "July", "August", "September",
00075   "October", "November", "December"
00076 };
00077 
00078 const char *_months_abbrev[] = 
00079 {
00080   "Jan", "Feb", "Mar",
00081   "Apr", "May", "Jun",
00082   "Jul", "Aug", "Sep",
00083   "Oct", "Nov", "Dec"
00084 };
00085 
00086 const int _ytab[2][12] = 
00087 {
00088   {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
00089   {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
00090 };
00091 
00092 struct tm *gmtime(const type::Time::epoch_t &timer, struct tm *tmbuf)
00093 {
00094   uint64_t dayclock, dayno;
00095   int year = EPOCH_YR;
00096 
00097   if (timer < 0)
00098     return NULL;
00099 
00100   dayclock = (uint64_t) timer % SECS_DAY;
00101   dayno = (uint64_t) timer / SECS_DAY;
00102 
00103   tmbuf->tm_sec = dayclock % 60;
00104   tmbuf->tm_min = (dayclock % 3600) / 60;
00105   tmbuf->tm_hour = dayclock / 3600;
00106   tmbuf->tm_wday = (dayno + 4) % 7; // Day 0 was a thursday
00107   while (dayno >= (uint64_t) YEARSIZE(year)) 
00108   {
00109     dayno -= YEARSIZE(year);
00110     year++;
00111   }
00112   tmbuf->tm_year = year - YEAR0;
00113   tmbuf->tm_yday = dayno;
00114   tmbuf->tm_mon = 0;
00115   while (dayno >= (uint64_t) _ytab[LEAPYEAR(year)][tmbuf->tm_mon]) 
00116   {
00117     dayno -= _ytab[LEAPYEAR(year)][tmbuf->tm_mon];
00118     tmbuf->tm_mon++;
00119   }
00120   tmbuf->tm_mday = dayno + 1;
00121   tmbuf->tm_isdst = 0;
00122 
00123   return tmbuf;
00124 }
00125 
00126 void gmtime(const type::Time::epoch_t &timer, type::Time &tmbuf)
00127 {
00128   uint64_t dayclock, dayno;
00129   int32_t year= EPOCH_YR;
00130 
00131   if (timer < 0)
00132     return;
00133 
00134   tmbuf.reset();
00135 
00136   dayclock= (uint64_t) timer % SECS_DAY;
00137   dayno= (uint64_t) timer / SECS_DAY;
00138 
00139   tmbuf.second= dayclock % 60;
00140   tmbuf.minute= (dayclock % 3600) / 60;
00141   tmbuf.hour= dayclock / 3600;
00142   while (dayno >= (uint64_t) YEARSIZE(year)) 
00143   {
00144     dayno -= YEARSIZE(year);
00145     year++;
00146   }
00147   tmbuf.year= year;
00148   while (dayno >= (uint64_t) _ytab[LEAPYEAR(year)][tmbuf.month]) 
00149   {
00150     dayno -= _ytab[LEAPYEAR(year)][tmbuf.month];
00151     tmbuf.month++;
00152   }
00153   tmbuf.month++;
00154   tmbuf.day= dayno +1;
00155   tmbuf.time_type= type::DRIZZLE_TIMESTAMP_DATETIME;
00156 }
00157 
00158 void localtime(const type::Time::epoch_t &timer, type::Time &tmbuf)
00159 {
00160   type::Time::epoch_t t;
00161 
00162   t = timer - _timezone;
00163   return util::gmtime(t, tmbuf);
00164 }
00165 
00166 struct tm *localtime(const type::Time::epoch_t &timer, struct tm *tmbuf)
00167 {
00168   type::Time::epoch_t t;
00169 
00170   t = timer - _timezone;
00171   return util::gmtime(t, tmbuf);
00172 }
00173 
00174 // We don't use this code.
00175 #if 0
00176 time_t mktime(struct tm *tmbuf)
00177 {
00178   long day, year;
00179   int tm_year;
00180   int yday, month;
00181   /*unsigned*/ long seconds;
00182   int overflow;
00183   long dst;
00184 
00185   tmbuf->tm_min += tmbuf->tm_sec / 60;
00186   tmbuf->tm_sec %= 60;
00187   if (tmbuf->tm_sec < 0) 
00188   {
00189     tmbuf->tm_sec += 60;
00190     tmbuf->tm_min--;
00191   }
00192   tmbuf->tm_hour += tmbuf->tm_min / 60;
00193   tmbuf->tm_min = tmbuf->tm_min % 60;
00194   if (tmbuf->tm_min < 0) 
00195   {
00196     tmbuf->tm_min += 60;
00197     tmbuf->tm_hour--;
00198   }
00199   day = tmbuf->tm_hour / 24;
00200   tmbuf->tm_hour= tmbuf->tm_hour % 24;
00201   if (tmbuf->tm_hour < 0) 
00202   {
00203     tmbuf->tm_hour += 24;
00204     day--;
00205   }
00206   tmbuf->tm_year += tmbuf->tm_mon / 12;
00207   tmbuf->tm_mon %= 12;
00208   if (tmbuf->tm_mon < 0) 
00209   {
00210     tmbuf->tm_mon += 12;
00211     tmbuf->tm_year--;
00212   }
00213   day += (tmbuf->tm_mday - 1);
00214   while (day < 0) 
00215   {
00216     if(--tmbuf->tm_mon < 0) 
00217     {
00218       tmbuf->tm_year--;
00219       tmbuf->tm_mon = 11;
00220     }
00221     day += _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon];
00222   }
00223   while (day >= _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon]) 
00224   {
00225     day -= _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon];
00226     if (++(tmbuf->tm_mon) == 12) 
00227     {
00228       tmbuf->tm_mon = 0;
00229       tmbuf->tm_year++;
00230     }
00231   }
00232   tmbuf->tm_mday = day + 1;
00233   year = EPOCH_YR;
00234   if (tmbuf->tm_year < year - YEAR0) return (time_t) -1;
00235   seconds = 0;
00236   day = 0;                      // Means days since day 0 now
00237   overflow = 0;
00238 
00239   // Assume that when day becomes negative, there will certainly
00240   // be overflow on seconds.
00241   // The check for overflow needs not to be done for leapyears
00242   // divisible by 400.
00243   // The code only works when year (1970) is not a leapyear.
00244   tm_year = tmbuf->tm_year + YEAR0;
00245 
00246   if (TIME_MAX / 365 < tm_year - year)
00247     overflow++;
00248   day = (tm_year - year) * 365;
00249   if (TIME_MAX - day < (tm_year - year) / 4 + 1) overflow++;
00250   day += (tm_year - year) / 4 + ((tm_year % 4) && tm_year % 4 < year % 4);
00251   day -= (tm_year - year) / 100 + ((tm_year % 100) && tm_year % 100 < year % 100);
00252   day += (tm_year - year) / 400 + ((tm_year % 400) && tm_year % 400 < year % 400);
00253 
00254   yday = month = 0;
00255   while (month < tmbuf->tm_mon)
00256   {
00257     yday += _ytab[LEAPYEAR(tm_year)][month];
00258     month++;
00259   }
00260   yday += (tmbuf->tm_mday - 1);
00261   if (day + yday < 0) overflow++;
00262   day += yday;
00263 
00264   tmbuf->tm_yday = yday;
00265   tmbuf->tm_wday = (day + 4) % 7;               // Day 0 was thursday (4)
00266 
00267   seconds = ((tmbuf->tm_hour * 60L) + tmbuf->tm_min) * 60L + tmbuf->tm_sec;
00268 
00269   if ((TIME_MAX - seconds) / SECS_DAY < day) overflow++;
00270   seconds += day * SECS_DAY;
00271 
00272   // Now adjust according to timezone and daylight saving time
00273   if (((_timezone > 0) && (TIME_MAX - _timezone < seconds))
00274       || ((_timezone < 0) && (seconds < -_timezone)))
00275           overflow++;
00276   seconds += _timezone;
00277 
00278   if (tmbuf->tm_isdst)
00279     dst = _dstbias;
00280   else 
00281     dst = 0;
00282 
00283   if (dst > seconds) overflow++;        // dst is always non-negative
00284   seconds -= dst;
00285 
00286   if (overflow) return (time_t) -1;
00287 
00288   if ((time_t) seconds != seconds) return (time_t) -1;
00289   return (time_t) seconds;
00290 }
00291 #endif
00292 
00293 } /* namespace util */
00294 } /* namespace drizzled */