Drizzled Public API Documentation

time_functions.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008-2009 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; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 
00021 /* Functions to handle date and time */
00022 
00023 #include <config.h>
00024 #include <drizzled/error.h>
00025 #include <drizzled/util/test.h>
00026 #include <drizzled/session.h>
00027 #include <drizzled/time_functions.h>
00028 #include <drizzled/charset.h>
00029 #include <drizzled/system_variables.h>
00030 #include <drizzled/sql_string.h>
00031 
00032 namespace drizzled {
00033 
00034 /* Some functions to calculate dates */
00035 
00036 
00037 int calc_weekday(long daynr,bool sunday_first_day_of_week)
00038 {
00039   return ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
00040 }
00041 
00042 
00043 uint32_t calc_week(type::Time *l_time, uint32_t week_behaviour, uint32_t *year)
00044 {
00045   uint32_t days;
00046   uint32_t daynr= calc_daynr(l_time->year,l_time->month,l_time->day);
00047   uint32_t first_daynr= calc_daynr(l_time->year,1,1);
00048   bool monday_first= test(week_behaviour & WEEK_MONDAY_FIRST);
00049   bool week_year= test(week_behaviour & WEEK_YEAR);
00050   bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
00051 
00052   uint32_t weekday= calc_weekday(first_daynr, !monday_first);
00053   *year=l_time->year;
00054 
00055   if (l_time->month == 1 && l_time->day <= 7-weekday)
00056   {
00057     if ((!week_year) && ((first_weekday && weekday != 0) || (!first_weekday && weekday >= 4)))
00058       return 0;
00059     week_year= 1;
00060     (*year)--;
00061     first_daynr-= (days=calc_days_in_year(*year));
00062     weekday= (weekday + 53*7- days) % 7;
00063   }
00064 
00065   if ((first_weekday && weekday != 0) ||
00066       (!first_weekday && weekday >= 4))
00067     days= daynr - (first_daynr+ (7-weekday));
00068   else
00069     days= daynr - (first_daynr - weekday);
00070 
00071   if (week_year && days >= 52*7)
00072   {
00073     weekday= (weekday + calc_days_in_year(*year)) % 7;
00074     if ((!first_weekday && weekday < 4) || (first_weekday && weekday == 0))
00075     {
00076       (*year)++;
00077       return 1;
00078     }
00079   }
00080   return days/7+1;
00081 }
00082 
00083 
00084 void get_date_from_daynr(long daynr,
00085                          uint32_t *ret_year,
00086                          uint32_t *ret_month,
00087                          uint32_t *ret_day)
00088 {
00089   uint32_t year,temp,leap_day,day_of_year,days_in_year;
00090   unsigned char *month_pos;
00091 
00092   if (daynr <= 365L || daynr >= 3652500)
00093   {           /* Fix if wrong daynr */
00094     *ret_year= *ret_month = *ret_day =0;
00095   }
00096   else
00097   {
00098     year= (uint32_t) (daynr*100 / 36525L);
00099     temp=(((year-1)/100+1)*3)/4;
00100     day_of_year=(uint32_t) (daynr - (long) year * 365L) - (year-1)/4 +temp;
00101     while (day_of_year > (days_in_year= calc_days_in_year(year)))
00102     {
00103       day_of_year-=days_in_year;
00104       (year)++;
00105     }
00106     leap_day=0;
00107     if (days_in_year == 366)
00108     {
00109       if (day_of_year > 31+28)
00110       {
00111         day_of_year--;
00112         if (day_of_year == 31+28)
00113           leap_day=1;   /* Handle leapyears leapday */
00114       }
00115     }
00116     *ret_month=1;
00117     for (month_pos= days_in_month ;
00118          day_of_year > (uint32_t) *month_pos ;
00119          day_of_year-= *(month_pos++), (*ret_month)++)
00120       ;
00121     *ret_year=year;
00122     *ret_day=day_of_year+leap_day;
00123   }
00124   return;
00125 }
00126 
00127 
00128 type::timestamp_t str_to_datetime_with_warn(Session& session, str_ref str, type::Time& l_time, uint32_t flags)
00129 {
00130   type::cut_t was_cut= type::VALID;
00131   type::timestamp_t ts_type= l_time.store(str.data(), str.size(), (flags | (session.variables.sql_mode & (MODE_INVALID_DATES | MODE_NO_ZERO_DATE))), was_cut);
00132   if (was_cut || ts_type <= type::DRIZZLE_TIMESTAMP_ERROR)
00133     make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, str, ts_type,  NULL);
00134   return ts_type;
00135 }
00136 
00137 
00138 bool str_to_time_with_warn(Session& session, str_ref str, type::Time& l_time)
00139 {
00140   int warning;
00141   bool ret_val= l_time.store(str.data(), str.size(), warning, type::DRIZZLE_TIMESTAMP_TIME);
00142   if (ret_val || warning)
00143     make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, str, type::DRIZZLE_TIMESTAMP_TIME, NULL);
00144   return ret_val;
00145 }
00146 
00147 
00148 void make_truncated_value_warning(Session& session, DRIZZLE_ERROR::enum_warning_level level, str_ref str_arg, type::timestamp_t time_type, const char *field_name)
00149 {
00150   char warn_buff[DRIZZLE_ERRMSG_SIZE];
00151   charset_info_st *cs= &my_charset_utf8_general_ci;
00152   char buff[128];
00153   String str(buff,(uint32_t) sizeof(buff), system_charset_info);
00154   str.copy(str_arg.data(), str_arg.size(), system_charset_info);
00155   assert(not str[str_arg.size()]);               // Ensure we have end 0 for snprintf
00156 
00157   const char *type_str;
00158   switch (time_type) 
00159   {
00160   case type::DRIZZLE_TIMESTAMP_DATE:
00161     type_str= "date";
00162     break;
00163 
00164   case type::DRIZZLE_TIMESTAMP_TIME:
00165     type_str= "time";
00166     break;
00167 
00168   case type::DRIZZLE_TIMESTAMP_DATETIME:  // FALLTHROUGH
00169   default:
00170     type_str= "datetime";
00171   }
00172 
00173   if (field_name)
00174   {
00175     cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
00176                        ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
00177                        type_str, str.c_ptr(), field_name,
00178                        (uint32_t) session.row_count);
00179   }
00180   else if (time_type > type::DRIZZLE_TIMESTAMP_ERROR)
00181   {
00182     cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), ER(ER_TRUNCATED_WRONG_VALUE), type_str, str.c_ptr());
00183   }
00184   else
00185   {
00186     cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), ER(ER_WRONG_VALUE), type_str, str.c_ptr());
00187   }
00188   push_warning(&session, level, ER_TRUNCATED_WRONG_VALUE, warn_buff);
00189 }
00190 
00191 
00192 bool
00193 calc_time_diff(type::Time *l_time1, type::Time *l_time2, int l_sign, int64_t *seconds_out,
00194                long *microseconds_out)
00195 {
00196   long days;
00197   bool neg;
00198   int64_t microseconds;
00199 
00200   /*
00201     We suppose that if first argument is DRIZZLE_TIMESTAMP_TIME
00202     the second argument should be TIMESTAMP_TIME also.
00203     We should check it before calc_time_diff call.
00204   */
00205   if (l_time1->time_type == type::DRIZZLE_TIMESTAMP_TIME)  // Time value
00206     days= (long)l_time1->day - l_sign * (long)l_time2->day;
00207   else
00208   {
00209     days= calc_daynr((uint32_t) l_time1->year,
00210                      (uint32_t) l_time1->month,
00211                      (uint32_t) l_time1->day);
00212     if (l_time2->time_type == type::DRIZZLE_TIMESTAMP_TIME)
00213       days-= l_sign * (long)l_time2->day;
00214     else
00215       days-= l_sign*calc_daynr((uint32_t) l_time2->year,
00216                                (uint32_t) l_time2->month,
00217                                (uint32_t) l_time2->day);
00218   }
00219 
00220   microseconds= ((int64_t)days*86400L +
00221                  (int64_t)(l_time1->hour*3600L +
00222                            l_time1->minute*60L +
00223                            l_time1->second) -
00224                  l_sign*(int64_t)(l_time2->hour*3600L +
00225                                   l_time2->minute*60L +
00226                                   l_time2->second)) * 1000000L +
00227     (int64_t)l_time1->second_part -
00228     l_sign*(int64_t)l_time2->second_part;
00229 
00230   neg= 0;
00231   if (microseconds < 0)
00232   {
00233     microseconds= -microseconds;
00234     neg= 1;
00235   }
00236   *seconds_out= microseconds/1000000L;
00237   *microseconds_out= (long) (microseconds%1000000L);
00238   return neg;
00239 }
00240 
00241 } /* namespace drizzled */