1/* Copyright (c) 2006, 2010, Oracle and/or its affiliates.
2 Copyright (c) 2011, 2016, MariaDB
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17#ifndef SQL_TIME_INCLUDED
18#define SQL_TIME_INCLUDED
19
20#include "my_time.h"
21#include "mysql_time.h" /* timestamp_type */
22#include "sql_error.h" /* Sql_condition */
23#include "structs.h" /* INTERVAL */
24
25typedef enum enum_mysql_timestamp_type timestamp_type;
26typedef struct st_date_time_format DATE_TIME_FORMAT;
27typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT;
28
29/* Flags for calc_week() function. */
30#define WEEK_MONDAY_FIRST 1
31#define WEEK_YEAR 2
32#define WEEK_FIRST_WEEKDAY 4
33
34ulong convert_period_to_month(ulong period);
35ulong convert_month_to_period(ulong month);
36void set_current_date(THD *thd, MYSQL_TIME *to);
37bool time_to_datetime(MYSQL_TIME *ltime);
38void time_to_daytime_interval(MYSQL_TIME *l_time);
39bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
40my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code);
41bool str_to_datetime_with_warn(CHARSET_INFO *cs, const char *str, size_t length, MYSQL_TIME *l_time,
42 ulonglong flags);
43bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
44 ulonglong fuzzydate,
45 const char *name);
46bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
47 ulonglong fuzzydate,
48 const char *name);
49bool int_to_datetime_with_warn(bool neg, ulonglong value, MYSQL_TIME *ltime,
50 ulonglong fuzzydate,
51 const char *name);
52
53bool time_to_datetime(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt);
54bool time_to_datetime_with_warn(THD *thd,
55 const MYSQL_TIME *tm, MYSQL_TIME *dt,
56 ulonglong fuzzydate);
57/*
58 Simply truncate the YYYY-MM-DD part to 0000-00-00
59 and change time_type to MYSQL_TIMESTAMP_TIME
60*/
61inline void datetime_to_time(MYSQL_TIME *ltime)
62{
63 DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE ||
64 ltime->time_type == MYSQL_TIMESTAMP_DATETIME);
65 DBUG_ASSERT(ltime->neg == 0);
66 ltime->year= ltime->month= ltime->day= 0;
67 ltime->time_type= MYSQL_TIMESTAMP_TIME;
68}
69
70
71/**
72 Convert DATE/DATETIME to TIME(dec)
73 using CURRENT_DATE in a non-old mode,
74 or using simple truncation in old mode (OLD_MODE_ZERO_DATE_TIME_CAST).
75
76 @param thd - the thread to get the variables.old_behaviour value from
77 @param dt - the DATE of DATETIME value to convert
78 @param[out] tm - store result here
79 @param dec - the desired scale. The fractional part of the result
80 is checked according to this parameter before returning
81 the conversion result. "dec" is important in the corner
82 cases near the max/min limits.
83 If the result is '838:59:59.999999' and the desired scale
84 is less than 6, an error is returned.
85 Note, dec is not important in the
86 OLD_MODE_ZERO_DATE_TIME_CAST old mode.
87
88 - in case of OLD_MODE_ZERO_DATE_TIME_CAST
89 the TIME part is simply truncated and "false" is returned.
90 - otherwise, the result is calculated effectively similar to:
91 TIMEDIFF(dt, CAST(CURRENT_DATE AS DATETIME))
92 If the difference fits into the supported TIME range, "false" is returned,
93 otherwise a warning is issued and "true" is returned.
94
95 @return false - on success
96 @return true - on error
97*/
98bool datetime_to_time_with_warn(THD *, const MYSQL_TIME *dt,
99 MYSQL_TIME *tm, uint dec);
100
101
102inline void datetime_to_date(MYSQL_TIME *ltime)
103{
104 DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE ||
105 ltime->time_type == MYSQL_TIMESTAMP_DATETIME);
106 DBUG_ASSERT(ltime->neg == 0);
107 ltime->second_part= ltime->hour= ltime->minute= ltime->second= 0;
108 ltime->time_type= MYSQL_TIMESTAMP_DATE;
109}
110inline void date_to_datetime(MYSQL_TIME *ltime)
111{
112 DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE ||
113 ltime->time_type == MYSQL_TIMESTAMP_DATETIME);
114 DBUG_ASSERT(ltime->neg == 0);
115 ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
116}
117void make_truncated_value_warning(THD *thd,
118 Sql_condition::enum_warning_level level,
119 const ErrConv *str_val,
120 timestamp_type time_type,
121 const char *field_name);
122
123static inline void make_truncated_value_warning(THD *thd,
124 Sql_condition::enum_warning_level level, const char *str_val, size_t str_length, timestamp_type time_type,
125 const char *field_name)
126{
127 const ErrConvString str(str_val, str_length, &my_charset_bin);
128 make_truncated_value_warning(thd, level, &str, time_type, field_name);
129}
130
131extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
132 const char *format_str,
133 uint format_length);
134extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd,
135 DATE_TIME_FORMAT *format);
136const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
137 timestamp_type type);
138bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec);
139
140/* MYSQL_TIME operations */
141bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
142 const INTERVAL &interval);
143bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
144 int l_sign, longlong *seconds_out, long *microseconds_out);
145int append_interval(String *str, interval_type int_type,
146 const INTERVAL &interval);
147/**
148 Calculate time difference between two MYSQL_TIME values and
149 store the result as an out MYSQL_TIME value in MYSQL_TIMESTAMP_TIME format.
150
151 The result can be outside of the supported TIME range.
152 For example, calc_time_diff('2002-01-01 00:00:00', '2001-01-01 00:00:00')
153 returns '8760:00:00'. So the caller might want to do check_time_range() or
154 adjust_time_range_with_warn() on the result of a calc_time_diff() call.
155
156 @param l_time1 - the minuend (TIME/DATE/DATETIME value)
157 @param l_time2 - the subtrahend TIME/DATE/DATETIME value
158 @param l_sign - +1 if absolute values are to be subtracted,
159 or -1 if absolute values are to be added.
160 @param[out] l_time3 - the result
161 @param fuzzydate - flags
162
163 @return true - if TIME_NO_ZERO_DATE was passed in flags and
164 the result appeared to be '00:00:00.000000'.
165 This is important when calc_time_diff() is called
166 when calculating DATE_ADD(TIMEDIFF(...),...)
167 @return false - otherwise
168*/
169bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
170 int lsign, MYSQL_TIME *l_time3, ulonglong fuzzydate);
171int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b);
172void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
173
174void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
175uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
176
177int calc_weekday(long daynr,bool sunday_first_day_of_week);
178bool parse_date_time_format(timestamp_type format_type,
179 const char *format, uint format_length,
180 DATE_TIME_FORMAT *date_time_format);
181/* Character set-aware version of str_to_time() */
182bool str_to_time(CHARSET_INFO *cs, const char *str,size_t length,
183 MYSQL_TIME *l_time, ulonglong fuzzydate,
184 MYSQL_TIME_STATUS *status);
185/* Character set-aware version of str_to_datetime() */
186bool str_to_datetime(CHARSET_INFO *cs,
187 const char *str, size_t length,
188 MYSQL_TIME *l_time, ulonglong flags,
189 MYSQL_TIME_STATUS *status);
190
191/* convenience wrapper */
192inline bool parse_date_time_format(timestamp_type format_type,
193 DATE_TIME_FORMAT *date_time_format)
194{
195 return parse_date_time_format(format_type,
196 date_time_format->format.str,
197 (uint) date_time_format->format.length,
198 date_time_format);
199}
200
201
202extern DATE_TIME_FORMAT global_date_format;
203extern DATE_TIME_FORMAT global_datetime_format;
204extern DATE_TIME_FORMAT global_time_format;
205extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
206extern LEX_CSTRING interval_type_to_name[];
207
208static inline bool
209non_zero_hhmmssuu(const MYSQL_TIME *ltime)
210{
211 return ltime->hour || ltime->minute || ltime->second || ltime->second_part;
212}
213static inline bool
214non_zero_YYMMDD(const MYSQL_TIME *ltime)
215{
216 return ltime->year || ltime->month || ltime->day;
217}
218static inline bool
219non_zero_date(const MYSQL_TIME *ltime)
220{
221 return non_zero_YYMMDD(ltime) ||
222 (ltime->time_type == MYSQL_TIMESTAMP_DATETIME &&
223 non_zero_hhmmssuu(ltime));
224}
225static inline bool
226check_date(const MYSQL_TIME *ltime, ulonglong flags, int *was_cut)
227{
228 return check_date(ltime, non_zero_date(ltime), flags, was_cut);
229}
230bool check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
231 timestamp_type ts_type);
232bool make_date_with_warn(MYSQL_TIME *ltime,
233 ulonglong fuzzy_date, timestamp_type ts_type);
234bool adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec);
235
236longlong pack_time(const MYSQL_TIME *my_time);
237void unpack_time(longlong packed, MYSQL_TIME *my_time,
238 enum_mysql_timestamp_type ts_type);
239
240#endif /* SQL_TIME_INCLUDED */
241