1 /* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef SQL_TIME_INCLUDED
24 #define SQL_TIME_INCLUDED
25 
26 #include "my_global.h"                          /* ulong */
27 #include "my_time.h"
28 #include "mysql_time.h"                         /* timestamp_type */
29 #include "sql_error.h"                          /* Sql_condition */
30 #include "structs.h"                            /* INTERVAL */
31 
32 typedef enum enum_mysql_timestamp_type timestamp_type;
33 typedef struct st_date_time_format DATE_TIME_FORMAT;
34 typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT;
35 
36 /* Flags for calc_week() function.  */
37 #define WEEK_MONDAY_FIRST    1
38 #define WEEK_YEAR            2
39 #define WEEK_FIRST_WEEKDAY   4
40 
41 ulong convert_period_to_month(ulong period);
42 ulong convert_month_to_period(ulong month);
43 void mix_date_and_time(MYSQL_TIME *ldate, const MYSQL_TIME *ltime);
44 void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
45 my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
46 bool datetime_with_no_zero_in_date_to_timeval(THD *thd, const MYSQL_TIME *t,
47                                               struct timeval *tm,
48                                               int *warnings);
49 bool datetime_to_timeval(THD *thd, const MYSQL_TIME *t,
50                          struct timeval *tm, int *warnings);
51 bool str_to_datetime_with_warn(String *str,  MYSQL_TIME *l_time, uint flags);
52 bool my_decimal_to_datetime_with_warn(const my_decimal *decimal,
53                                       MYSQL_TIME *ltime, uint flags);
54 bool my_double_to_datetime_with_warn(double nr, MYSQL_TIME *ltime, uint flags);
55 bool my_longlong_to_datetime_with_warn(longlong nr,
56                                        MYSQL_TIME *ltime, uint flags);
57 bool my_decimal_to_time_with_warn(const my_decimal *decimal,
58                                   MYSQL_TIME *ltime);
59 bool my_double_to_time_with_warn(double nr, MYSQL_TIME *ltime);
60 bool my_longlong_to_time_with_warn(longlong nr, MYSQL_TIME *ltime);
61 bool str_to_time_with_warn(String *str, MYSQL_TIME *l_time);
62 void time_to_datetime(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt);
datetime_to_time(MYSQL_TIME * ltime)63 inline void datetime_to_time(MYSQL_TIME *ltime)
64 {
65   ltime->year= ltime->month= ltime->day= 0;
66   ltime->time_type= MYSQL_TIMESTAMP_TIME;
67 }
datetime_to_date(MYSQL_TIME * ltime)68 inline void datetime_to_date(MYSQL_TIME *ltime)
69 {
70   ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
71   ltime->time_type= MYSQL_TIMESTAMP_DATE;
72 }
date_to_datetime(MYSQL_TIME * ltime)73 inline void date_to_datetime(MYSQL_TIME *ltime)
74 {
75   ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
76 }
77 void make_truncated_value_warning(THD *thd,
78                                   Sql_condition::enum_warning_level level,
79                                   ErrConvString val,
80                                   timestamp_type time_type,
81                                   const char *field_name);
make_truncated_value_warning(ErrConvString val,timestamp_type time_type)82 inline void make_truncated_value_warning(ErrConvString val,
83                                          timestamp_type time_type)
84 {
85   make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
86                                val, time_type, NullS);
87 }
88 extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
89 					       const char *format_str,
90 					       uint format_length);
91 extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd,
92 					       DATE_TIME_FORMAT *format);
93 const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
94 				     timestamp_type type);
95 void make_date(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
96                String *str);
97 void make_time(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
98                String *str, uint dec);
99 void make_datetime(const DATE_TIME_FORMAT *format, const MYSQL_TIME *l_time,
100                    String *str, uint dec);
101 bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec);
102 
103 /* MYSQL_TIME operations */
104 bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
105                        INTERVAL interval);
106 bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
107                     int l_sign, longlong *seconds_out, long *microseconds_out);
108 int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b);
109 void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
110 void calc_time_from_sec(MYSQL_TIME *to, longlong seconds, long microseconds);
111 uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
112 
113 int calc_weekday(long daynr,bool sunday_first_day_of_week);
114 bool parse_date_time_format(timestamp_type format_type,
115                             const char *format, uint format_length,
116                             DATE_TIME_FORMAT *date_time_format);
117 /* Character set-aware version of str_to_time() */
118 bool str_to_time(const CHARSET_INFO *cs, const char *str, uint length,
119                  MYSQL_TIME *l_time, uint flags, MYSQL_TIME_STATUS *status);
120 static inline bool
str_to_time(const String * str,MYSQL_TIME * ltime,uint flags,MYSQL_TIME_STATUS * status)121 str_to_time(const String *str, MYSQL_TIME *ltime, uint flags,
122             MYSQL_TIME_STATUS *status)
123 {
124   return str_to_time(str->charset(), str->ptr(), str->length(),
125                      ltime, flags, status);
126 }
127 
128 bool time_add_nanoseconds_with_round(MYSQL_TIME *ltime, uint nanoseconds,
129                                      int *warnings);
130 /* Character set-aware version of str_to_datetime() */
131 bool str_to_datetime(const CHARSET_INFO *cs,
132                      const char *str, uint length,
133                      MYSQL_TIME *l_time, uint flags,
134                      MYSQL_TIME_STATUS *status);
135 static inline bool
str_to_datetime(const String * str,MYSQL_TIME * ltime,uint flags,MYSQL_TIME_STATUS * status)136 str_to_datetime(const String *str, MYSQL_TIME *ltime, uint flags,
137                 MYSQL_TIME_STATUS *status)
138 {
139   return str_to_datetime(str->charset(), str->ptr(), str->length(),
140                          ltime, flags, status);
141 }
142 
143 bool datetime_add_nanoseconds_with_round(MYSQL_TIME *ltime,
144                                          uint nanoseconds, int *warnings);
145 
146 /* convenience wrapper */
parse_date_time_format(timestamp_type format_type,DATE_TIME_FORMAT * date_time_format)147 inline bool parse_date_time_format(timestamp_type format_type,
148                                    DATE_TIME_FORMAT *date_time_format)
149 {
150   return parse_date_time_format(format_type,
151                                 date_time_format->format.str,
152                                 date_time_format->format.length,
153                                 date_time_format);
154 }
155 
156 
157 extern DATE_TIME_FORMAT global_date_format;
158 extern DATE_TIME_FORMAT global_datetime_format;
159 extern DATE_TIME_FORMAT global_time_format;
160 extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
161 extern LEX_STRING interval_type_to_name[];
162 
163 /* Date/time rounding and truncation functions */
my_time_fraction_remainder(long nr,uint decimals)164 inline long my_time_fraction_remainder(long nr, uint decimals)
165 {
166   DBUG_ASSERT(decimals <= DATETIME_MAX_DECIMALS);
167   return nr % (long) log_10_int[DATETIME_MAX_DECIMALS - decimals];
168 }
my_time_trunc(MYSQL_TIME * ltime,uint decimals)169 inline void my_time_trunc(MYSQL_TIME *ltime, uint decimals)
170 {
171   ltime->second_part-= my_time_fraction_remainder(ltime->second_part, decimals);
172 }
my_datetime_trunc(MYSQL_TIME * ltime,uint decimals)173 inline void my_datetime_trunc(MYSQL_TIME *ltime, uint decimals)
174 {
175   return my_time_trunc(ltime, decimals);
176 }
my_timeval_trunc(struct timeval * tv,uint decimals)177 inline void my_timeval_trunc(struct timeval *tv, uint decimals)
178 {
179   tv->tv_usec-= my_time_fraction_remainder(tv->tv_usec, decimals);
180 }
181 bool my_time_round(MYSQL_TIME *ltime, uint decimals);
182 bool my_datetime_round(MYSQL_TIME *ltime, uint decimals, int *warnings);
183 bool my_timeval_round(struct timeval *tv, uint decimals);
184 
185 
TIME_to_ulonglong_datetime_round(const MYSQL_TIME * ltime)186 inline ulonglong TIME_to_ulonglong_datetime_round(const MYSQL_TIME *ltime)
187 {
188   // Catch simple cases
189   if (ltime->second_part < 500000)
190     return TIME_to_ulonglong_datetime(ltime);
191   if (ltime->second < 59)
192     return TIME_to_ulonglong_datetime(ltime) + 1;
193   // Corner case e.g. 'YYYY-MM-DD hh:mm:59.5'. Proceed with slower method.
194   int warnings= 0;
195   MYSQL_TIME tmp= *ltime;
196   my_datetime_round(&tmp, 0, &warnings);
197   return TIME_to_ulonglong_datetime(&tmp);// + TIME_microseconds_round(ltime);
198 }
199 
200 
TIME_to_ulonglong_time_round(const MYSQL_TIME * ltime)201 inline ulonglong TIME_to_ulonglong_time_round(const MYSQL_TIME *ltime)
202 {
203   if (ltime->second_part < 500000)
204     return TIME_to_ulonglong_time(ltime);
205   if (ltime->second < 59)
206     return TIME_to_ulonglong_time(ltime) + 1;
207   // Corner case e.g. 'hh:mm:59.5'. Proceed with slower method.
208   MYSQL_TIME tmp= *ltime;
209   my_time_round(&tmp, 0);
210   return TIME_to_ulonglong_time(&tmp);
211 }
212 
213 
TIME_to_ulonglong_round(const MYSQL_TIME * ltime)214 inline ulonglong TIME_to_ulonglong_round(const MYSQL_TIME *ltime)
215 {
216   switch (ltime->time_type)
217   {
218   case MYSQL_TIMESTAMP_TIME:
219     return TIME_to_ulonglong_time_round(ltime);
220   case MYSQL_TIMESTAMP_DATETIME:
221     return TIME_to_ulonglong_datetime_round(ltime);
222   case MYSQL_TIMESTAMP_DATE:
223     return TIME_to_ulonglong_date(ltime);
224   default:
225     DBUG_ASSERT(0);
226     return 0;
227   }
228 }
229 
230 
TIME_microseconds(const MYSQL_TIME * ltime)231 inline double TIME_microseconds(const MYSQL_TIME *ltime)
232 {
233   return (double) ltime->second_part / 1000000;
234 }
235 
TIME_to_double_datetime(const MYSQL_TIME * ltime)236 inline double TIME_to_double_datetime(const MYSQL_TIME *ltime)
237 {
238   return (double) TIME_to_ulonglong_datetime(ltime) + TIME_microseconds(ltime);
239 }
240 
241 
TIME_to_double_time(const MYSQL_TIME * ltime)242 inline double TIME_to_double_time(const MYSQL_TIME *ltime)
243 {
244   return (double) TIME_to_ulonglong_time(ltime) + TIME_microseconds(ltime);
245 }
246 
247 
TIME_to_double(const MYSQL_TIME * ltime)248 inline double TIME_to_double(const MYSQL_TIME *ltime)
249 {
250   return (double) TIME_to_ulonglong(ltime) + TIME_microseconds(ltime);
251 }
252 
253 
254 static inline bool
check_fuzzy_date(const MYSQL_TIME * ltime,uint fuzzydate)255 check_fuzzy_date(const MYSQL_TIME *ltime, uint fuzzydate)
256 {
257   return !(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day);
258 }
259 
260 static inline bool
non_zero_date(const MYSQL_TIME * ltime)261 non_zero_date(const MYSQL_TIME *ltime)
262 {
263   return ltime->year || ltime->month || ltime->day;
264 }
265 
266 static inline bool
non_zero_time(const MYSQL_TIME * ltime)267 non_zero_time(const MYSQL_TIME *ltime)
268 {
269   return ltime->hour || ltime->minute || ltime->second || ltime->second_part;
270 }
271 
272 longlong TIME_to_longlong_packed(const MYSQL_TIME *tm,
273                                  enum enum_field_types type);
274 void TIME_from_longlong_packed(MYSQL_TIME *ltime,
275                                enum enum_field_types type,
276                                longlong packed_value);
277 my_decimal *my_decimal_from_datetime_packed(my_decimal *dec,
278                                             enum enum_field_types type,
279                                             longlong packed_value);
280 
281 longlong longlong_from_datetime_packed(enum enum_field_types type,
282                                        longlong packed_value);
283 
284 double double_from_datetime_packed(enum enum_field_types type,
285                                    longlong packed_value);
286 
287 static inline
field_type_to_timestamp_type(enum enum_field_types type)288 timestamp_type field_type_to_timestamp_type(enum enum_field_types type)
289 {
290   switch (type)
291   {
292   case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME;
293   case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE;
294   case MYSQL_TYPE_TIMESTAMP:
295   case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME;
296   default: return MYSQL_TIMESTAMP_NONE;
297   }
298 }
299 #endif /* SQL_TIME_INCLUDED */
300