Drizzled Public API Documentation

time_functions.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2008-2009 Sun Microsystems, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 
21 /* Functions to handle date and time */
22 
23 #include <config.h>
24 #include <drizzled/error.h>
25 #include <drizzled/util/test.h>
26 #include <drizzled/session.h>
27 #include <drizzled/time_functions.h>
28 #include <drizzled/charset.h>
29 #include <drizzled/system_variables.h>
30 #include <drizzled/sql_string.h>
31 
32 namespace drizzled {
33 
34 /* Some functions to calculate dates */
35 
36 
37 int calc_weekday(long daynr,bool sunday_first_day_of_week)
38 {
39  return ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
40 }
41 
42 
43 uint32_t calc_week(type::Time *l_time, uint32_t week_behaviour, uint32_t *year)
44 {
45  uint32_t days;
46  uint32_t daynr= calc_daynr(l_time->year,l_time->month,l_time->day);
47  uint32_t first_daynr= calc_daynr(l_time->year,1,1);
48  bool monday_first= test(week_behaviour & WEEK_MONDAY_FIRST);
49  bool week_year= test(week_behaviour & WEEK_YEAR);
50  bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
51 
52  uint32_t weekday= calc_weekday(first_daynr, !monday_first);
53  *year=l_time->year;
54 
55  if (l_time->month == 1 && l_time->day <= 7-weekday)
56  {
57  if ((!week_year) && ((first_weekday && weekday != 0) || (!first_weekday && weekday >= 4)))
58  return 0;
59  week_year= 1;
60  (*year)--;
61  first_daynr-= (days=calc_days_in_year(*year));
62  weekday= (weekday + 53*7- days) % 7;
63  }
64 
65  if ((first_weekday && weekday != 0) ||
66  (!first_weekday && weekday >= 4))
67  days= daynr - (first_daynr+ (7-weekday));
68  else
69  days= daynr - (first_daynr - weekday);
70 
71  if (week_year && days >= 52*7)
72  {
73  weekday= (weekday + calc_days_in_year(*year)) % 7;
74  if ((!first_weekday && weekday < 4) || (first_weekday && weekday == 0))
75  {
76  (*year)++;
77  return 1;
78  }
79  }
80  return days/7+1;
81 }
82 
83 
84 void get_date_from_daynr(long daynr,
85  uint32_t *ret_year,
86  uint32_t *ret_month,
87  uint32_t *ret_day)
88 {
89  uint32_t year,temp,leap_day,day_of_year,days_in_year;
90  unsigned char *month_pos;
91 
92  if (daynr <= 365L || daynr >= 3652500)
93  { /* Fix if wrong daynr */
94  *ret_year= *ret_month = *ret_day =0;
95  }
96  else
97  {
98  year= (uint32_t) (daynr*100 / 36525L);
99  temp=(((year-1)/100+1)*3)/4;
100  day_of_year=(uint32_t) (daynr - (long) year * 365L) - (year-1)/4 +temp;
101  while (day_of_year > (days_in_year= calc_days_in_year(year)))
102  {
103  day_of_year-=days_in_year;
104  (year)++;
105  }
106  leap_day=0;
107  if (days_in_year == 366)
108  {
109  if (day_of_year > 31+28)
110  {
111  day_of_year--;
112  if (day_of_year == 31+28)
113  leap_day=1; /* Handle leapyears leapday */
114  }
115  }
116  *ret_month=1;
117  for (month_pos= days_in_month ;
118  day_of_year > (uint32_t) *month_pos ;
119  day_of_year-= *(month_pos++), (*ret_month)++)
120  ;
121  *ret_year=year;
122  *ret_day=day_of_year+leap_day;
123  }
124  return;
125 }
126 
127 
128 type::timestamp_t str_to_datetime_with_warn(Session& session, str_ref str, type::Time& l_time, uint32_t flags)
129 {
130  type::cut_t was_cut= type::VALID;
131  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);
132  if (was_cut || ts_type <= type::DRIZZLE_TIMESTAMP_ERROR)
133  make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, str, ts_type, NULL);
134  return ts_type;
135 }
136 
137 
138 bool str_to_time_with_warn(Session& session, str_ref str, type::Time& l_time)
139 {
140  int warning;
141  bool ret_val= l_time.store(str.data(), str.size(), warning, type::DRIZZLE_TIMESTAMP_TIME);
142  if (ret_val || warning)
143  make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, str, type::DRIZZLE_TIMESTAMP_TIME, NULL);
144  return ret_val;
145 }
146 
147 
148 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)
149 {
150  char warn_buff[DRIZZLE_ERRMSG_SIZE];
151  charset_info_st *cs= &my_charset_utf8_general_ci;
152  char buff[128];
153  String str(buff,(uint32_t) sizeof(buff), system_charset_info);
154  str.copy(str_arg.data(), str_arg.size(), system_charset_info);
155  assert(not str[str_arg.size()]); // Ensure we have end 0 for snprintf
156 
157  const char *type_str;
158  switch (time_type)
159  {
160  case type::DRIZZLE_TIMESTAMP_DATE:
161  type_str= "date";
162  break;
163 
164  case type::DRIZZLE_TIMESTAMP_TIME:
165  type_str= "time";
166  break;
167 
168  case type::DRIZZLE_TIMESTAMP_DATETIME: // FALLTHROUGH
169  default:
170  type_str= "datetime";
171  }
172 
173  if (field_name)
174  {
175  cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
176  ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
177  type_str, str.c_ptr(), field_name,
178  (uint32_t) session.row_count);
179  }
180  else if (time_type > type::DRIZZLE_TIMESTAMP_ERROR)
181  {
182  cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), ER(ER_TRUNCATED_WRONG_VALUE), type_str, str.c_ptr());
183  }
184  else
185  {
186  cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff), ER(ER_WRONG_VALUE), type_str, str.c_ptr());
187  }
188  push_warning(&session, level, ER_TRUNCATED_WRONG_VALUE, warn_buff);
189 }
190 
191 
192 bool
193 calc_time_diff(type::Time *l_time1, type::Time *l_time2, int l_sign, int64_t *seconds_out,
194  long *microseconds_out)
195 {
196  long days;
197  bool neg;
198  int64_t microseconds;
199 
200  /*
201  We suppose that if first argument is DRIZZLE_TIMESTAMP_TIME
202  the second argument should be TIMESTAMP_TIME also.
203  We should check it before calc_time_diff call.
204  */
205  if (l_time1->time_type == type::DRIZZLE_TIMESTAMP_TIME) // Time value
206  days= (long)l_time1->day - l_sign * (long)l_time2->day;
207  else
208  {
209  days= calc_daynr((uint32_t) l_time1->year,
210  (uint32_t) l_time1->month,
211  (uint32_t) l_time1->day);
212  if (l_time2->time_type == type::DRIZZLE_TIMESTAMP_TIME)
213  days-= l_sign * (long)l_time2->day;
214  else
215  days-= l_sign*calc_daynr((uint32_t) l_time2->year,
216  (uint32_t) l_time2->month,
217  (uint32_t) l_time2->day);
218  }
219 
220  microseconds= ((int64_t)days*86400L +
221  (int64_t)(l_time1->hour*3600L +
222  l_time1->minute*60L +
223  l_time1->second) -
224  l_sign*(int64_t)(l_time2->hour*3600L +
225  l_time2->minute*60L +
226  l_time2->second)) * 1000000L +
227  (int64_t)l_time1->second_part -
228  l_sign*(int64_t)l_time2->second_part;
229 
230  neg= 0;
231  if (microseconds < 0)
232  {
233  microseconds= -microseconds;
234  neg= 1;
235  }
236  *seconds_out= microseconds/1000000L;
237  *microseconds_out= (long) (microseconds%1000000L);
238  return neg;
239 }
240 
241 } /* namespace drizzled */
TODO: Rename this file - func.h is stupid.
uint32_t days_in_year(const uint32_t year, enum calendar calendar)
Definition: calendar.cc:218