Drizzled Public API Documentation

calendar.cc

Go to the documentation of this file.
00001 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00027 #include <config.h>
00028 
00029 #if TIME_WITH_SYS_TIME
00030 # include <sys/time.h>
00031 # include <time.h>
00032 #else
00033 # if HAVE_SYS_TIME_H
00034 #  include <sys/time.h>
00035 # else
00036 #  include <time.h>
00037 # endif
00038 #endif
00039 #include <cstdlib>
00040 
00041 #include <drizzled/calendar.h>
00042 
00043 namespace drizzled
00044 {
00045 
00047 static const uint32_t __leap_days_in_month[12]=       {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00048 static const uint32_t __normal_days_in_month[12]=     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00049 static const uint32_t __leap_days_to_end_month[13]=   {0, 31, 60, 91, 121, 151, 182, 213, 244, 274, 305, 335, 366};
00050 static const uint32_t __normal_days_to_end_month[13]= {0, 31, 59, 90, 120, 150, 181, 212, 243, 273, 304, 334, 365};
00051 
00056 inline static const uint32_t* days_in_month(uint32_t y, enum calendar c) 
00057 {
00058   if (is_leap_year(y, c))
00059     return __leap_days_in_month;
00060   else
00061     return __normal_days_in_month;
00062 }
00063 
00064 inline static const uint32_t* days_to_end_month(uint32_t y, enum calendar c) 
00065 {
00066   if (is_leap_year(y, c))
00067     return __leap_days_to_end_month;
00068   else
00069     return __normal_days_to_end_month;
00070 }
00071 
00072 
00101 int64_t julian_day_number_from_gregorian_date(uint32_t year, uint32_t month, uint32_t day)
00102 {
00103   int64_t day_number;
00104   int64_t a= (14 - month) / 12;
00105   int64_t y= year + 4800 - a;
00106   int64_t m= month + (12 * a) - 3;
00107 
00108   day_number= day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - (y / 100) + (y / 400) - 32045;
00109   return day_number;
00110 }
00111 
00119 int64_t absolute_day_number_to_julian_day_number(int64_t absolute_day)
00120 {
00121   return absolute_day + JULIAN_DAY_NUMBER_AT_ABSOLUTE_DAY_ONE;
00122 }
00123 
00131 int64_t julian_day_number_to_absolute_day_number(int64_t julian_day)
00132 {
00133   return julian_day - JULIAN_DAY_NUMBER_AT_ABSOLUTE_DAY_ONE;
00134 }
00135 
00148 void gregorian_date_from_julian_day_number(int64_t julian_day
00149                                          , uint32_t *year_out
00150                                          , uint32_t *month_out
00151                                          , uint32_t *day_out)
00152 {
00153   int64_t j = julian_day + 32044;
00154   int64_t g = j / 146097;
00155   int64_t dg = j % 146097;
00156   int64_t c = (dg / 36524 + 1) * 3 / 4;
00157   int64_t dc = dg - c * 36524;
00158   int64_t b = dc / 1461;
00159   int64_t db = dc % 1461;
00160   int64_t a = (db / 365 + 1) * 3 / 4;
00161   int64_t da = db - a * 365;
00162   int64_t y = g * 400 + c * 100 + b * 4 + a;
00163   int64_t m = (da * 5 + 308) / 153 - 2;
00164   int64_t d = da - (m + 4) * 153 / 5 + 122;
00165   int64_t Y = y - 4800 + (m + 2) / 12;
00166   int64_t M = (m + 2) % 12 + 1;
00167   int64_t D = (int64_t)((double)d + 1.5);
00168 
00169   /* Push out parameters */
00170   *year_out= (uint32_t) Y;
00171   *month_out= (uint32_t) M;
00172   *day_out= (uint32_t) D;
00173 }
00174 
00185 void gregorian_date_from_absolute_day_number(int64_t absolute_day
00186                                            , uint32_t *year_out
00187                                            , uint32_t *month_out
00188                                            , uint32_t *day_out)
00189 {
00190   gregorian_date_from_julian_day_number(
00191       absolute_day_number_to_julian_day_number(absolute_day)
00192     , year_out
00193     , month_out
00194     , day_out);
00195 }
00196 
00218 inline uint32_t days_in_year(const uint32_t year, enum calendar calendar)
00219 {
00220   if (calendar == GREGORIAN)
00221     return days_in_year_gregorian(year);
00222   return days_in_year_julian(year);
00223 }
00224 
00230 inline uint32_t days_in_year_julian(const uint32_t year)
00231 {
00232   /* Short-circuit. No odd years can be leap years... */
00233   return (year & 3) == 0;
00234 }
00235 
00241 inline uint32_t days_in_year_gregorian(const uint32_t year)
00242 {
00243   /* Short-circuit. No odd years can be leap years... */
00244   if ((year & 1) == 1)
00245     return 365;
00246   return (            
00247             (year & 3) == 0 
00248             && (year % 100 || ((year % 400 == 0) && year)) 
00249             ? 366 
00250             : 365
00251          );
00252 }
00253 
00279 uint32_t day_of_week(int64_t day_number
00280                    , bool sunday_is_first_day_of_week)
00281 {
00282   uint32_t tmp= (uint32_t) (day_number % 7);
00283   /* 0 returned from above modulo is a Monday */
00284   if (sunday_is_first_day_of_week)
00285     tmp= (tmp == 6 ? 0 : tmp + 1);
00286   return tmp;
00287 }
00288 
00297 bool is_valid_gregorian_date(uint32_t year, uint32_t month, uint32_t day)
00298 {
00299   if (year < 1)
00300     return false;
00301   if (month != 2)
00302     return (day <= __normal_days_in_month[month - 1]);
00303   else
00304   {
00305     const uint32_t *p_months= days_in_month(year, (enum calendar) GREGORIAN);
00306     return (day <= p_months[1]);
00307   }
00308 }
00309 
00317 uint32_t days_in_gregorian_year_month(uint32_t year, uint32_t month)
00318 {
00319   const uint32_t *p_months= days_in_month(year, GREGORIAN);
00320   return p_months[month - 1];
00321 }
00322 
00336 bool in_unix_epoch_range(uint32_t year,
00337                          uint32_t month,
00338                          uint32_t day,
00339                          uint32_t hour,
00340                          uint32_t minute,
00341                          uint32_t second)
00342 {
00343   if (month == 0 || day == 0)
00344     return false;
00345 
00346   if (year < UNIX_EPOCH_MAX_YEARS
00347       && year >= UNIX_EPOCH_MIN_YEARS)
00348     return true;
00349 
00350   if (year < UNIX_EPOCH_MIN_YEARS)
00351     return false;
00352 
00353   if (year == UNIX_EPOCH_MAX_YEARS)
00354   {
00355     if (month > 1)
00356     {
00357       return false;
00358     }
00359     if (day > 19)
00360     {
00361       return false;
00362     }
00363     else if (day < 19)
00364     {
00365       return true;
00366     }
00367     else
00368     {
00369       /* We are on the final day of UNIX Epoch */
00370       uint32_t seconds= (hour * 60 * 60)
00371                       + (minute * 60)
00372                       + (second);
00373       if (seconds <= ((3 * 60 * 60) + (14 * 60) + 7))
00374         return true;
00375       return false;
00376     }
00377   }
00378   return false;
00379 }
00380 
00394 uint32_t week_number_from_gregorian_date(uint32_t year
00395                                        , uint32_t month
00396                                        , uint32_t day
00397                                        , bool sunday_is_first_day_of_week)
00398 {
00399   struct tm broken_time;
00400 
00401   broken_time.tm_year= year;
00402   broken_time.tm_mon= month - 1; /* struct tm has non-ordinal months */
00403   broken_time.tm_mday= day;
00404 
00405   /* fill out the rest of our tm fields. */
00406   (void) mktime(&broken_time);
00407 
00408   char result[3]; /* 3 is enough space for a max 2-digit week number */
00409   size_t result_len= strftime(result
00410                             , sizeof(result)
00411                             , (sunday_is_first_day_of_week ? "%U" : "%W")
00412                             , &broken_time);
00413 
00414   if (result_len != 0)
00415     return (uint32_t) atoi(result);
00416   return 0;
00417 }
00418 
00437 uint32_t iso_week_number_from_gregorian_date(uint32_t year
00438                                            , uint32_t month
00439                                            , uint32_t day)
00440 {
00441   struct tm broken_time;
00442 
00443   broken_time.tm_year= year;
00444   broken_time.tm_mon= month - 1; /* struct tm has non-ordinal months */
00445   broken_time.tm_mday= day;
00446 
00447   /* fill out the rest of our tm fields. */
00448   (void) mktime(&broken_time);
00449 
00450   char result[3]; /* 3 is enough space for a max 2-digit week number */
00451   size_t result_len= strftime(result
00452                             , sizeof(result)
00453                             , "%V"
00454                             , &broken_time);
00455 
00456 
00457   if (result_len == 0)
00458     return 0; /* Not valid for ISO8601:1988 */
00459 
00460   uint32_t week_number= (uint32_t) atoi(result);
00461 
00462   return week_number;
00463 }
00464 
00471 uint32_t year_month_to_months(uint32_t year_month)
00472 {
00473   if (year_month == 0)
00474     return 0L;
00475 
00476   uint32_t years= year_month / 100;
00477   if (years < CALENDAR_YY_PART_YEAR)
00478     years+= 2000;
00479   else if (years < 100)
00480     years+= 1900;
00481 
00482   uint32_t months= year_month % 100;
00483   return (years * 12) + (months - 1);
00484 }
00485 
00492 uint32_t months_to_year_month(uint32_t months)
00493 {
00494   if (months == 0L)
00495     return 0L;
00496 
00497   uint32_t years= (months / 12);
00498 
00499   if (years < 100)
00500     years+= (years < CALENDAR_YY_PART_YEAR) ? 2000 : 1900;
00501 
00502   return (years * 100) + (months % 12) + 1;
00503 }
00504 
00505 } /* namespace drizzled */