1 /* Copyright (c) 2006, 2014, 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 "mysqld.h" /* current_thd */
31
32 struct Date_time_format
33 {
34 uchar positions[8];
35 char time_separator; /* Separator between hour and minute */
36 uint flag; /* For future */
37 LEX_STRING format;
38 };
39
40 struct Interval
41 {
42 ulong year, month, day, hour;
43 ulonglong minute, second, second_part;
44 bool neg;
45 };
46
47 struct Known_date_time_format
48 {
49 const char *format_name;
50 const char *date_format;
51 const char *datetime_format;
52 const char *time_format;
53 };
54
55 /* Flags for calc_week() function. */
56 #define WEEK_MONDAY_FIRST 1
57 #define WEEK_YEAR 2
58 #define WEEK_FIRST_WEEKDAY 4
59
60 ulong convert_period_to_month(ulong period);
61 ulong convert_month_to_period(ulong month);
62 void mix_date_and_time(MYSQL_TIME *ldate, const MYSQL_TIME *ltime);
63 void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
64 my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
65 bool datetime_with_no_zero_in_date_to_timeval(THD *thd, const MYSQL_TIME *t,
66 struct timeval *tm,
67 int *warnings);
68 bool datetime_to_timeval(THD *thd, const MYSQL_TIME *t,
69 struct timeval *tm, int *warnings);
70 bool str_to_datetime_with_warn(String *str, MYSQL_TIME *l_time,
71 my_time_flags_t flags);
72 bool my_decimal_to_datetime_with_warn(const my_decimal *decimal,
73 MYSQL_TIME *ltime, my_time_flags_t flags);
74 bool my_double_to_datetime_with_warn(double nr, MYSQL_TIME *ltime,
75 my_time_flags_t flags);
76 bool my_longlong_to_datetime_with_warn(longlong nr, MYSQL_TIME *ltime,
77 my_time_flags_t flags);
78 bool my_decimal_to_time_with_warn(const my_decimal *decimal,
79 MYSQL_TIME *ltime);
80 bool my_double_to_time_with_warn(double nr, MYSQL_TIME *ltime);
81 bool my_longlong_to_time_with_warn(longlong nr, MYSQL_TIME *ltime);
82 bool str_to_time_with_warn(String *str, MYSQL_TIME *l_time);
83 void time_to_datetime(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt);
datetime_to_time(MYSQL_TIME * ltime)84 inline void datetime_to_time(MYSQL_TIME *ltime)
85 {
86 ltime->year= ltime->month= ltime->day= 0;
87 ltime->time_type= MYSQL_TIMESTAMP_TIME;
88 }
datetime_to_date(MYSQL_TIME * ltime)89 inline void datetime_to_date(MYSQL_TIME *ltime)
90 {
91 ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
92 ltime->time_type= MYSQL_TIMESTAMP_DATE;
93 }
date_to_datetime(MYSQL_TIME * ltime)94 inline void date_to_datetime(MYSQL_TIME *ltime)
95 {
96 ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
97 }
98 void make_truncated_value_warning(THD *thd,
99 Sql_condition::enum_severity_level level,
100 ErrConvString val,
101 timestamp_type time_type,
102 const char *field_name);
make_truncated_value_warning(ErrConvString val,timestamp_type time_type)103 inline void make_truncated_value_warning(ErrConvString val,
104 timestamp_type time_type)
105 {
106 make_truncated_value_warning(current_thd, Sql_condition::SL_WARNING,
107 val, time_type, NullS);
108 }
109 extern Date_time_format *date_time_format_copy(THD *thd,
110 Date_time_format *format);
111 const char *get_date_time_format_str(Known_date_time_format *format,
112 timestamp_type type);
113 void make_date(const Date_time_format *format, const MYSQL_TIME *l_time,
114 String *str);
115 void make_time(const Date_time_format *format, const MYSQL_TIME *l_time,
116 String *str, uint dec);
117 void make_datetime(const Date_time_format *format, const MYSQL_TIME *l_time,
118 String *str, uint dec);
119 bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec);
120
121 /* MYSQL_TIME operations */
122 bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
123 Interval interval);
124 bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
125 int l_sign, longlong *seconds_out, long *microseconds_out);
126 int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b);
127 void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
128 void calc_time_from_sec(MYSQL_TIME *to, longlong seconds, long microseconds);
129 uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
130
131 int calc_weekday(long daynr,bool sunday_first_day_of_week);
132
133 /* Character set-aware version of str_to_time() */
134 bool str_to_time(const CHARSET_INFO *cs, const char *str, size_t length,
135 MYSQL_TIME *l_time, my_time_flags_t flags,
136 MYSQL_TIME_STATUS *status);
str_to_time(const String * str,MYSQL_TIME * ltime,my_time_flags_t flags,MYSQL_TIME_STATUS * status)137 static inline bool str_to_time(const String *str, MYSQL_TIME *ltime,
138 my_time_flags_t flags, MYSQL_TIME_STATUS *status)
139 {
140 return str_to_time(str->charset(), str->ptr(), str->length(),
141 ltime, flags, status);
142 }
143
144 bool time_add_nanoseconds_with_round(MYSQL_TIME *ltime, uint nanoseconds,
145 int *warnings);
146 /* Character set-aware version of str_to_datetime() */
147 bool str_to_datetime(const CHARSET_INFO *cs,
148 const char *str, size_t length,
149 MYSQL_TIME *l_time, my_time_flags_t flags,
150 MYSQL_TIME_STATUS *status);
str_to_datetime(const String * str,MYSQL_TIME * ltime,my_time_flags_t flags,MYSQL_TIME_STATUS * status)151 static inline bool str_to_datetime(const String *str, MYSQL_TIME *ltime,
152 my_time_flags_t flags,
153 MYSQL_TIME_STATUS *status)
154 {
155 return str_to_datetime(str->charset(), str->ptr(), str->length(),
156 ltime, flags, status);
157 }
158
159 bool datetime_add_nanoseconds_with_round(MYSQL_TIME *ltime,
160 uint nanoseconds, int *warnings);
161
162 bool parse_date_time_format(timestamp_type format_type,
163 Date_time_format *date_time_format);
164
165 extern Date_time_format global_date_format;
166 extern Date_time_format global_datetime_format;
167 extern Date_time_format global_time_format;
168 extern Known_date_time_format known_date_time_formats[];
169 extern LEX_STRING interval_type_to_name[];
170
171 /* Date/time rounding and truncation functions */
my_time_fraction_remainder(long nr,uint decimals)172 inline long my_time_fraction_remainder(long nr, uint decimals)
173 {
174 DBUG_ASSERT(decimals <= DATETIME_MAX_DECIMALS);
175 return nr % (long) log_10_int[DATETIME_MAX_DECIMALS - decimals];
176 }
my_time_trunc(MYSQL_TIME * ltime,uint decimals)177 inline void my_time_trunc(MYSQL_TIME *ltime, uint decimals)
178 {
179 ltime->second_part-= my_time_fraction_remainder(ltime->second_part, decimals);
180 }
my_datetime_trunc(MYSQL_TIME * ltime,uint decimals)181 inline void my_datetime_trunc(MYSQL_TIME *ltime, uint decimals)
182 {
183 return my_time_trunc(ltime, decimals);
184 }
my_timeval_trunc(struct timeval * tv,uint decimals)185 inline void my_timeval_trunc(struct timeval *tv, uint decimals)
186 {
187 tv->tv_usec-= my_time_fraction_remainder(tv->tv_usec, decimals);
188 }
189 bool my_time_round(MYSQL_TIME *ltime, uint decimals);
190 bool my_datetime_round(MYSQL_TIME *ltime, uint decimals, int *warnings);
191 bool my_timeval_round(struct timeval *tv, uint decimals);
192
193
TIME_to_ulonglong_datetime_round(const MYSQL_TIME * ltime)194 inline ulonglong TIME_to_ulonglong_datetime_round(const MYSQL_TIME *ltime)
195 {
196 // Catch simple cases
197 if (ltime->second_part < 500000)
198 return TIME_to_ulonglong_datetime(ltime);
199 if (ltime->second < 59)
200 return TIME_to_ulonglong_datetime(ltime) + 1;
201 // Corner case e.g. 'YYYY-MM-DD hh:mm:59.5'. Proceed with slower method.
202 int warnings= 0;
203 MYSQL_TIME tmp= *ltime;
204 my_datetime_round(&tmp, 0, &warnings);
205 return TIME_to_ulonglong_datetime(&tmp);// + TIME_microseconds_round(ltime);
206 }
207
208
TIME_to_ulonglong_time_round(const MYSQL_TIME * ltime)209 inline ulonglong TIME_to_ulonglong_time_round(const MYSQL_TIME *ltime)
210 {
211 if (ltime->second_part < 500000)
212 return TIME_to_ulonglong_time(ltime);
213 if (ltime->second < 59)
214 return TIME_to_ulonglong_time(ltime) + 1;
215 // Corner case e.g. 'hh:mm:59.5'. Proceed with slower method.
216 MYSQL_TIME tmp= *ltime;
217 my_time_round(&tmp, 0);
218 return TIME_to_ulonglong_time(&tmp);
219 }
220
221
TIME_to_ulonglong_round(const MYSQL_TIME * ltime)222 inline ulonglong TIME_to_ulonglong_round(const MYSQL_TIME *ltime)
223 {
224 switch (ltime->time_type)
225 {
226 case MYSQL_TIMESTAMP_TIME:
227 return TIME_to_ulonglong_time_round(ltime);
228 case MYSQL_TIMESTAMP_DATETIME:
229 return TIME_to_ulonglong_datetime_round(ltime);
230 case MYSQL_TIMESTAMP_DATE:
231 return TIME_to_ulonglong_date(ltime);
232 default:
233 DBUG_ASSERT(0);
234 return 0;
235 }
236 }
237
238
TIME_microseconds(const MYSQL_TIME * ltime)239 inline double TIME_microseconds(const MYSQL_TIME *ltime)
240 {
241 return (double) ltime->second_part / 1000000;
242 }
243
TIME_to_double_datetime(const MYSQL_TIME * ltime)244 inline double TIME_to_double_datetime(const MYSQL_TIME *ltime)
245 {
246 return (double) TIME_to_ulonglong_datetime(ltime) + TIME_microseconds(ltime);
247 }
248
249
TIME_to_double_time(const MYSQL_TIME * ltime)250 inline double TIME_to_double_time(const MYSQL_TIME *ltime)
251 {
252 return (double) TIME_to_ulonglong_time(ltime) + TIME_microseconds(ltime);
253 }
254
255
TIME_to_double(const MYSQL_TIME * ltime)256 inline double TIME_to_double(const MYSQL_TIME *ltime)
257 {
258 return (double) TIME_to_ulonglong(ltime) + TIME_microseconds(ltime);
259 }
260
261
check_fuzzy_date(const MYSQL_TIME * ltime,my_time_flags_t fuzzydate)262 static inline bool check_fuzzy_date(const MYSQL_TIME *ltime,
263 my_time_flags_t fuzzydate)
264 {
265 return !(fuzzydate & TIME_FUZZY_DATE) && (!ltime->month || !ltime->day);
266 }
267
268 static inline bool
non_zero_date(const MYSQL_TIME * ltime)269 non_zero_date(const MYSQL_TIME *ltime)
270 {
271 return ltime->year || ltime->month || ltime->day;
272 }
273
274 static inline bool
non_zero_time(const MYSQL_TIME * ltime)275 non_zero_time(const MYSQL_TIME *ltime)
276 {
277 return ltime->hour || ltime->minute || ltime->second || ltime->second_part;
278 }
279
280 longlong TIME_to_longlong_packed(const MYSQL_TIME *tm,
281 enum enum_field_types type);
282 void TIME_from_longlong_packed(MYSQL_TIME *ltime,
283 enum enum_field_types type,
284 longlong packed_value);
285 my_decimal *my_decimal_from_datetime_packed(my_decimal *dec,
286 enum enum_field_types type,
287 longlong packed_value);
288
289 longlong longlong_from_datetime_packed(enum enum_field_types type,
290 longlong packed_value);
291
292 double double_from_datetime_packed(enum enum_field_types type,
293 longlong packed_value);
294
295 static inline
field_type_to_timestamp_type(enum enum_field_types type)296 timestamp_type field_type_to_timestamp_type(enum enum_field_types type)
297 {
298 switch (type)
299 {
300 case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME;
301 case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE;
302 case MYSQL_TYPE_TIMESTAMP:
303 case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME;
304 default: return MYSQL_TIMESTAMP_NONE;
305 }
306 }
307 #endif /* SQL_TIME_INCLUDED */
308