MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sql_time.cc
1 /* Copyright (c) 2000, 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 as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 
17 /* Functions to handle date and time */
18 
19 #include "sql_priv.h"
20 #include "unireg.h" // REQUIRED by other includes
21 #include "sql_time.h"
22 #include "tztime.h" // struct Time_zone
23 #include "sql_class.h" // THD, MODE_INVALID_DATES, MODE_NO_ZERO_DATE
24 #include <m_ctype.h>
25 
26 
27  /* Some functions to calculate dates */
28 
29 #ifndef TESTTIME
30 
31 /*
32  Name description of interval names used in statements.
33 
34  'interval_type_to_name' is ordered and sorted on interval size and
35  interval complexity.
36  Order of elements in 'interval_type_to_name' should correspond to
37  the order of elements in 'interval_type' enum
38 
39  See also interval_type, interval_names
40 */
41 
42 LEX_STRING interval_type_to_name[INTERVAL_LAST] = {
43  { C_STRING_WITH_LEN("YEAR")},
44  { C_STRING_WITH_LEN("QUARTER")},
45  { C_STRING_WITH_LEN("MONTH")},
46  { C_STRING_WITH_LEN("WEEK")},
47  { C_STRING_WITH_LEN("DAY")},
48  { C_STRING_WITH_LEN("HOUR")},
49  { C_STRING_WITH_LEN("MINUTE")},
50  { C_STRING_WITH_LEN("SECOND")},
51  { C_STRING_WITH_LEN("MICROSECOND")},
52  { C_STRING_WITH_LEN("YEAR_MONTH")},
53  { C_STRING_WITH_LEN("DAY_HOUR")},
54  { C_STRING_WITH_LEN("DAY_MINUTE")},
55  { C_STRING_WITH_LEN("DAY_SECOND")},
56  { C_STRING_WITH_LEN("HOUR_MINUTE")},
57  { C_STRING_WITH_LEN("HOUR_SECOND")},
58  { C_STRING_WITH_LEN("MINUTE_SECOND")},
59  { C_STRING_WITH_LEN("DAY_MICROSECOND")},
60  { C_STRING_WITH_LEN("HOUR_MICROSECOND")},
61  { C_STRING_WITH_LEN("MINUTE_MICROSECOND")},
62  { C_STRING_WITH_LEN("SECOND_MICROSECOND")}
63 };
64 
65  /* Calc weekday from daynr */
66  /* Returns 0 for monday, 1 for tuesday .... */
67 
68 int calc_weekday(long daynr,bool sunday_first_day_of_week)
69 {
70  DBUG_ENTER("calc_weekday");
71  DBUG_RETURN ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
72 }
73 
74 /*
75  The bits in week_format has the following meaning:
76  WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week
77  If set Monday is first day of week
78  WEEK_YEAR (1) If not set Week is in range 0-53
79 
80  Week 0 is returned for the the last week of the previous year (for
81  a date at start of january) In this case one can get 53 for the
82  first week of next year. This flag ensures that the week is
83  relevant for the given year. Note that this flag is only
84  releveant if WEEK_JANUARY is not set.
85 
86  If set Week is in range 1-53.
87 
88  In this case one may get week 53 for a date in January (when
89  the week is that last week of previous year) and week 1 for a
90  date in December.
91 
92  WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according
93  to ISO 8601:1988
94  If set The week that contains the first
95  'first-day-of-week' is week 1.
96 
97  ISO 8601:1988 means that if the week containing January 1 has
98  four or more days in the new year, then it is week 1;
99  Otherwise it is the last week of the previous year, and the
100  next week is week 1.
101 */
102 
103 uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year)
104 {
105  uint days;
106  ulong daynr=calc_daynr(l_time->year,l_time->month,l_time->day);
107  ulong first_daynr=calc_daynr(l_time->year,1,1);
108  bool monday_first= test(week_behaviour & WEEK_MONDAY_FIRST);
109  bool week_year= test(week_behaviour & WEEK_YEAR);
110  bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
111 
112  uint weekday=calc_weekday(first_daynr, !monday_first);
113  *year=l_time->year;
114 
115  if (l_time->month == 1 && l_time->day <= 7-weekday)
116  {
117  if (!week_year &&
118  ((first_weekday && weekday != 0) ||
119  (!first_weekday && weekday >= 4)))
120  return 0;
121  week_year= 1;
122  (*year)--;
123  first_daynr-= (days=calc_days_in_year(*year));
124  weekday= (weekday + 53*7- days) % 7;
125  }
126 
127  if ((first_weekday && weekday != 0) ||
128  (!first_weekday && weekday >= 4))
129  days= daynr - (first_daynr+ (7-weekday));
130  else
131  days= daynr - (first_daynr - weekday);
132 
133  if (week_year && days >= 52*7)
134  {
135  weekday= (weekday + calc_days_in_year(*year)) % 7;
136  if ((!first_weekday && weekday < 4) ||
137  (first_weekday && weekday == 0))
138  {
139  (*year)++;
140  return 1;
141  }
142  }
143  return days/7+1;
144 }
145 
146  /* Change a daynr to year, month and day */
147  /* Daynr 0 is returned as date 00.00.00 */
148 
149 void get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month,
150  uint *ret_day)
151 {
152  uint year,temp,leap_day,day_of_year,days_in_year;
153  uchar *month_pos;
154  DBUG_ENTER("get_date_from_daynr");
155 
156  if (daynr <= 365L || daynr >= 3652500)
157  { /* Fix if wrong daynr */
158  *ret_year= *ret_month = *ret_day =0;
159  }
160  else
161  {
162  year= (uint) (daynr*100 / 36525L);
163  temp=(((year-1)/100+1)*3)/4;
164  day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp;
165  while (day_of_year > (days_in_year= calc_days_in_year(year)))
166  {
167  day_of_year-=days_in_year;
168  (year)++;
169  }
170  leap_day=0;
171  if (days_in_year == 366)
172  {
173  if (day_of_year > 31+28)
174  {
175  day_of_year--;
176  if (day_of_year == 31+28)
177  leap_day=1; /* Handle leapyears leapday */
178  }
179  }
180  *ret_month=1;
181  for (month_pos= days_in_month ;
182  day_of_year > (uint) *month_pos ;
183  day_of_year-= *(month_pos++), (*ret_month)++)
184  ;
185  *ret_year=year;
186  *ret_day=day_of_year+leap_day;
187  }
188  DBUG_VOID_RETURN;
189 }
190 
191  /* Functions to handle periods */
192 
193 ulong convert_period_to_month(ulong period)
194 {
195  ulong a,b;
196  if (period == 0)
197  return 0L;
198  if ((a=period/100) < YY_PART_YEAR)
199  a+=2000;
200  else if (a < 100)
201  a+=1900;
202  b=period%100;
203  return a*12+b-1;
204 }
205 
206 
207 ulong convert_month_to_period(ulong month)
208 {
209  ulong year;
210  if (month == 0L)
211  return 0L;
212  if ((year=month/12) < 100)
213  {
214  year+=(year < YY_PART_YEAR) ? 2000 : 1900;
215  }
216  return year*100+month%12+1;
217 }
218 
219 
220 /*
221  Convert a string to 8-bit representation,
222  for use in str_to_time/str_to_date/str_to_date.
223 
224  In the future to_ascii() can be extended to convert
225  non-ASCII digits to ASCII digits
226  (for example, ARABIC-INDIC, DEVANAGARI, BENGALI, and so on)
227  so DATE/TIME/DATETIME values understand digits in the
228  respected scripts.
229 */
230 static uint
231 to_ascii(const CHARSET_INFO *cs,
232  const char *src, uint src_length,
233  char *dst, uint dst_length)
234 
235 {
236  int cnvres;
237  my_wc_t wc;
238  const char *srcend= src + src_length;
239  char *dst0= dst, *dstend= dst + dst_length - 1;
240  while (dst < dstend &&
241  (cnvres= (cs->cset->mb_wc)(cs, &wc,
242  (const uchar*) src,
243  (const uchar*) srcend)) > 0 &&
244  wc < 128)
245  {
246  src+= cnvres;
247  *dst++= wc;
248  }
249  *dst= '\0';
250  return dst - dst0;
251 }
252 
253 
254 /* Character set-aware version of str_to_time() */
255 bool str_to_time(const CHARSET_INFO *cs, const char *str,uint length,
256  MYSQL_TIME *l_time, uint flags, MYSQL_TIME_STATUS *status)
257 {
258  char cnv[MAX_TIME_FULL_WIDTH + 3]; // +3 for nanoseconds (for rounding)
259  if ((cs->state & MY_CS_NONASCII) != 0)
260  {
261  length= to_ascii(cs, str, length, cnv, sizeof(cnv));
262  str= cnv;
263  }
264  return str_to_time(str, length, l_time, status) ||
265  (!(flags & TIME_NO_NSEC_ROUNDING) &&
266  time_add_nanoseconds_with_round(l_time, status->nanoseconds,
267  &status->warnings));
268 }
269 
270 
271 /* Character set-aware version of str_to_datetime() */
272 bool str_to_datetime(const CHARSET_INFO *cs,
273  const char *str, uint length,
274  MYSQL_TIME *l_time, uint flags,
275  MYSQL_TIME_STATUS *status)
276 {
277  char cnv[MAX_DATETIME_FULL_WIDTH + 3]; // +3 for nanoseconds (for rounding)
278  if ((cs->state & MY_CS_NONASCII) != 0)
279  {
280  length= to_ascii(cs, str, length, cnv, sizeof(cnv));
281  str= cnv;
282  }
283  return str_to_datetime(str, length, l_time, flags, status) ||
284  (!(flags & TIME_NO_NSEC_ROUNDING) &&
285  datetime_add_nanoseconds_with_round(l_time,
286  status->nanoseconds,
287  &status->warnings));
288 }
289 
290 
299 bool time_add_nanoseconds_with_round(MYSQL_TIME *ltime,
300  uint nanoseconds, int *warnings)
301 {
302  /* We expect correct input data */
303  DBUG_ASSERT(nanoseconds < 1000000000);
304  DBUG_ASSERT(!check_time_mmssff_range(ltime));
305 
306  if (nanoseconds < 500)
307  return false;
308 
309  ltime->second_part+= (nanoseconds + 500) / 1000;
310  if (ltime->second_part < 1000000)
311  goto ret;
312 
313  ltime->second_part%= 1000000;
314  if (ltime->second < 59)
315  {
316  ltime->second++;
317  goto ret;
318  }
319 
320  ltime->second= 0;
321  if (ltime->minute < 59)
322  {
323  ltime->minute++;
324  goto ret;
325  }
326  ltime->minute= 0;
327  ltime->hour++;
328 
329 ret:
330  /*
331  We can get '838:59:59.000001' at this point, which
332  is bigger than the maximum possible value '838:59:59.000000'.
333  Checking only "hour > 838" is not enough.
334  Do full adjust_time_range().
335  */
336  adjust_time_range(ltime, warnings);
337  return false;
338 }
339 
340 
349 bool datetime_add_nanoseconds_with_round(MYSQL_TIME *ltime,
350  uint nanoseconds, int *warnings)
351 {
352  DBUG_ASSERT(nanoseconds < 1000000000);
353  if (nanoseconds < 500)
354  return false;
355 
356  ltime->second_part+= (nanoseconds + 500) / 1000;
357  if (ltime->second_part < 1000000)
358  return false;
359 
360  ltime->second_part%= 1000000;
361  INTERVAL interval;
362  memset(&interval, 0, sizeof(interval));
363  interval.second= 1;
364  /* date_add_interval cannot handle bad dates */
365  if (check_date(ltime, non_zero_date(ltime),
366  (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE), warnings))
367  return true;
368 
369  if (date_add_interval(ltime, INTERVAL_SECOND, interval))
370  {
371  *warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
372  return true;
373  }
374  return false;
375 }
376 
377 
378 /*
379  Convert a timestamp string to a MYSQL_TIME value and produce a warning
380  if string was truncated during conversion.
381 
382  NOTE
383  See description of str_to_datetime() for more information.
384 */
385 bool
386 str_to_datetime_with_warn(String *str, MYSQL_TIME *l_time, uint flags)
387 {
388  MYSQL_TIME_STATUS status;
389  THD *thd= current_thd;
390  bool ret_val= str_to_datetime(str, l_time,
391  (flags | (thd->variables.sql_mode &
392  (MODE_INVALID_DATES | MODE_NO_ZERO_DATE))),
393  &status);
394  if (ret_val || status.warnings)
395  make_truncated_value_warning(ErrConvString(str), l_time->time_type);
396  return ret_val;
397 }
398 
399 
400 /*
401  Convert lldiv_t to datetime.
402 
403  @param lld The value to convert from.
404  @param OUT ltime The variable to convert to.
405  @param flags Conversion flags.
406  @param IN/OUT warnings Warning flags.
407  @return False on success, true on error.
408 */
409 static bool
410 lldiv_t_to_datetime(lldiv_t lld, MYSQL_TIME *ltime, uint flags, int *warnings)
411 {
412  if (lld.rem < 0 || // Catch negative numbers with zero int part, e.g: -0.1
413  number_to_datetime(lld.quot, ltime, flags, warnings) == LL(-1))
414  {
415  /* number_to_datetime does not clear ltime in case of ZERO DATE */
416  set_zero_time(ltime, MYSQL_TIMESTAMP_ERROR);
417  if (!*warnings) /* Neither sets warnings in case of ZERO DATE */
418  *warnings|= MYSQL_TIME_WARN_TRUNCATED;
419  return true;
420  }
421  else if (ltime->time_type == MYSQL_TIMESTAMP_DATE)
422  {
423  /*
424  Generate a warning in case of DATE with fractional part:
425  20011231.1234 -> '2001-12-31'
426  unless the caller does not want the warning: for example, CAST does.
427  */
428  if (lld.rem && !(flags & TIME_NO_DATE_FRAC_WARN))
429  *warnings|= MYSQL_TIME_WARN_TRUNCATED;
430  }
431  else if (!(flags & TIME_NO_NSEC_ROUNDING))
432  {
433  ltime->second_part= lld.rem / 1000;
434  return datetime_add_nanoseconds_with_round(ltime, lld.rem % 1000, warnings);
435  }
436  return false;
437 }
438 
439 
447 bool
448 my_decimal_to_datetime_with_warn(const my_decimal *decimal,
449  MYSQL_TIME *ltime, uint flags)
450 {
451  lldiv_t lld;
452  int warnings= 0;
453  bool rc;
454 
455  if ((rc= my_decimal2lldiv_t(0, decimal, &lld)))
456  {
457  warnings|= MYSQL_TIME_WARN_TRUNCATED;
458  set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
459  }
460  else
461  rc= lldiv_t_to_datetime(lld, ltime, flags, &warnings);
462 
463  if (warnings)
464  make_truncated_value_warning(ErrConvString(decimal), ltime->time_type);
465  return rc;
466 }
467 
468 
476 bool
477 my_double_to_datetime_with_warn(double nr, MYSQL_TIME *ltime, uint flags)
478 {
479  lldiv_t lld;
480  int warnings= 0;
481  bool rc;
482 
483  if ((rc= (double2lldiv_t(nr, &lld) != E_DEC_OK)))
484  {
485  warnings|= MYSQL_TIME_WARN_TRUNCATED;
486  set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
487  }
488  else
489  rc= lldiv_t_to_datetime(lld, ltime, flags, &warnings);
490 
491  if (warnings)
492  make_truncated_value_warning(ErrConvString(nr), ltime->time_type);
493  return rc;
494 }
495 
496 
503 bool
504 my_longlong_to_datetime_with_warn(longlong nr, MYSQL_TIME *ltime, uint flags)
505 {
506  int warnings= 0;
507  bool rc= number_to_datetime(nr, ltime, flags, &warnings) == LL(-1);
508  if (warnings)
509  make_truncated_value_warning(ErrConvString(nr), MYSQL_TIMESTAMP_NONE);
510  return rc;
511 }
512 
513 
514 /*
515  Convert lldiv_t value to time with nanosecond rounding.
516 
517  @param lld The value to convert from.
518  @param OUT ltime The variable to convert to,
519  @param flags Conversion flags.
520  @param IN/OUT warnings Warning flags.
521  @return False on success, true on error.
522 */
523 static bool lldiv_t_to_time(lldiv_t lld, MYSQL_TIME *ltime, int *warnings)
524 {
525  if (number_to_time(lld.quot, ltime, warnings))
526  return true;
527  /*
528  Both lld.quot and lld.rem can give negative result value,
529  thus combine them using "|=".
530  */
531  if ((ltime->neg|= (lld.rem < 0)))
532  lld.rem= -lld.rem;
533  ltime->second_part= lld.rem / 1000;
534  return time_add_nanoseconds_with_round(ltime, lld.rem % 1000, warnings);
535 }
536 
537 
538 /*
539  Convert decimal number to TIME
540  @param decimal_value The number to convert from.
541  @param OUT ltime The variable to convert to.
542  @param flags Conversion flags.
543  @return False on success, true on error.
544 */
545 bool my_decimal_to_time_with_warn(const my_decimal *decimal, MYSQL_TIME *ltime)
546 {
547  lldiv_t lld;
548  int warnings= 0;
549  bool rc;
550 
551  if ((rc= my_decimal2lldiv_t(0, decimal, &lld)))
552  {
553  warnings|= MYSQL_TIME_WARN_TRUNCATED;
554  set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
555  }
556  else
557  rc= lldiv_t_to_time(lld, ltime, &warnings);
558 
559  if (warnings)
560  make_truncated_value_warning(ErrConvString(decimal), MYSQL_TIMESTAMP_TIME);
561  return rc;
562 }
563 
564 
565 /*
566  Convert double number to TIME
567 
568  @param nr The number to convert from.
569  @param OUT ltime The variable to convert to.
570  @param flags Conversion flags.
571  @return False on success, true on error.
572 */
573 bool my_double_to_time_with_warn(double nr, MYSQL_TIME *ltime)
574 {
575  lldiv_t lld;
576  int warnings= 0;
577  bool rc;
578 
579  if ((rc= (double2lldiv_t(nr, &lld) != E_DEC_OK)))
580  {
581  warnings|= MYSQL_TIME_WARN_TRUNCATED;
582  set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
583  }
584  else
585  rc= lldiv_t_to_time(lld, ltime, &warnings);
586 
587  if (warnings)
588  make_truncated_value_warning(ErrConvString(nr), MYSQL_TIMESTAMP_TIME);
589  return rc;
590 }
591 
592 
593 
594 /*
595  Convert longlong number to TIME
596  @param nr The number to convert from.
597  @param OUT ltime The variable to convert to.
598  @param flags Conversion flags.
599  @return False on success, true on error.
600 */
601 bool my_longlong_to_time_with_warn(longlong nr, MYSQL_TIME *ltime)
602 {
603  int warnings= 0;
604  bool rc= number_to_time(nr, ltime, &warnings);
605  if (warnings)
606  make_truncated_value_warning(ErrConvString(nr), MYSQL_TIMESTAMP_TIME);
607  return rc;
608 }
609 
610 
624 my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *in_dst_time_gap)
625 {
626  my_time_t timestamp;
627 
628  *in_dst_time_gap= 0;
629 
630  timestamp= thd->time_zone()->TIME_to_gmt_sec(t, in_dst_time_gap);
631  if (timestamp)
632  {
633  return timestamp;
634  }
635 
636  /* If we are here we have range error. */
637  return(0);
638 }
639 
640 
669 bool datetime_with_no_zero_in_date_to_timeval(THD *thd,
670  const MYSQL_TIME *ltime,
671  struct timeval *tm,
672  int *warnings)
673 {
674  if (!ltime->month) /* Zero date */
675  {
676  DBUG_ASSERT(!ltime->year && !ltime->day);
677  if (non_zero_time(ltime))
678  {
679  /*
680  Return error for zero date with non-zero time, e.g.:
681  '0000-00-00 10:20:30' or '0000-00-00 00:00:00.123456'
682  */
683  *warnings|= MYSQL_TIME_WARN_TRUNCATED;
684  return true;
685  }
686  tm->tv_sec= tm->tv_usec= 0; // '0000-00-00 00:00:00.000000'
687  return false;
688  }
689 
690  my_bool in_dst_time_gap;
691  if (!(tm->tv_sec= TIME_to_timestamp(current_thd, ltime, &in_dst_time_gap)))
692  {
693  /*
694  Date was outside of the supported timestamp range.
695  For example: '3001-01-01 00:00:00' or '1000-01-01 00:00:00'
696  */
697  *warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
698  return true;
699  }
700  else if (in_dst_time_gap)
701  {
702  /*
703  Set MYSQL_TIME_WARN_INVALID_TIMESTAMP warning to indicate
704  that date was fine but pointed to winter/summer time switch gap.
705  In this case tm is set to the fist second after gap.
706  For example: '2003-03-30 02:30:00 MSK' -> '2003-03-30 03:00:00 MSK'
707  */
708  *warnings|= MYSQL_TIME_WARN_INVALID_TIMESTAMP;
709  }
710  tm->tv_usec= ltime->second_part;
711  return false;
712 }
713 
714 
742 bool datetime_to_timeval(THD *thd, const MYSQL_TIME *ltime,
743  struct timeval *tm, int *warnings)
744 {
745  return
746  check_date(ltime, non_zero_date(ltime), TIME_NO_ZERO_IN_DATE, warnings) ||
747  datetime_with_no_zero_in_date_to_timeval(current_thd, ltime, tm, warnings);
748 }
749 
750 
751 /*
752  Convert a time string to a MYSQL_TIME struct and produce a warning
753  if string was cut during conversion.
754 
755  NOTE
756  See str_to_time() for more info.
757 */
758 bool
759 str_to_time_with_warn(String *str, MYSQL_TIME *l_time)
760 {
761  MYSQL_TIME_STATUS status;
762  bool ret_val= str_to_time(str, l_time, 0, &status);
763  if (ret_val || status.warnings)
764  make_truncated_value_warning(ErrConvString(str), MYSQL_TIMESTAMP_TIME);
765  return ret_val;
766 }
767 
768 
776 void time_to_datetime(THD *thd, const MYSQL_TIME *ltime, MYSQL_TIME *ltime2)
777 {
778  thd->variables.time_zone->gmt_sec_to_TIME(ltime2, thd->query_start());
779  ltime2->hour= ltime2->minute= ltime2->second= ltime2->second_part= 0;
780  ltime2->time_type= MYSQL_TIMESTAMP_DATE;
781  mix_date_and_time(ltime2, ltime);
782 }
783 
784 
785 /*
786  Convert a system time structure to TIME
787 */
788 
789 void localtime_to_TIME(MYSQL_TIME *to, struct tm *from)
790 {
791  to->neg=0;
792  to->second_part=0;
793  to->year= (int) ((from->tm_year+1900) % 10000);
794  to->month= (int) from->tm_mon+1;
795  to->day= (int) from->tm_mday;
796  to->hour= (int) from->tm_hour;
797  to->minute= (int) from->tm_min;
798  to->second= (int) from->tm_sec;
799 }
800 
801 void calc_time_from_sec(MYSQL_TIME *to, longlong seconds, long microseconds)
802 {
803  long t_seconds;
804  // to->neg is not cleared, it may already be set to a useful value
805  to->time_type= MYSQL_TIMESTAMP_TIME;
806  to->year= 0;
807  to->month= 0;
808  to->day= 0;
809  DBUG_ASSERT(seconds < (0xFFFFFFFFLL * 3600LL));
810  to->hour= (long) (seconds / 3600L);
811  t_seconds= (long) (seconds % 3600L);
812  to->minute= t_seconds/60L;
813  to->second= t_seconds%60L;
814  to->second_part= microseconds;
815 }
816 
817 
818 /*
819  Parse a format string specification
820 
821  SYNOPSIS
822  parse_date_time_format()
823  format_type Format of string (time, date or datetime)
824  format_str String to parse
825  format_length Length of string
826  date_time_format Format to fill in
827 
828  NOTES
829  Fills in date_time_format->positions for all date time parts.
830 
831  positions marks the position for a datetime element in the format string.
832  The position array elements are in the following order:
833  YYYY-DD-MM HH-MM-DD.FFFFFF AM
834  0 1 2 3 4 5 6 7
835 
836  If positions[0]= 5, it means that year will be the forth element to
837  read from the parsed date string.
838 
839  RETURN
840  0 ok
841  1 error
842 */
843 
844 bool parse_date_time_format(timestamp_type format_type,
845  const char *format, uint format_length,
846  DATE_TIME_FORMAT *date_time_format)
847 {
848  uint offset= 0, separators= 0;
849  const char *ptr= format, *format_str;
850  const char *end= ptr+format_length;
851  uchar *dt_pos= date_time_format->positions;
852  /* need_p is set if we are using AM/PM format */
853  bool need_p= 0, allow_separator= 0;
854  ulong part_map= 0, separator_map= 0;
855  const char *parts[16];
856 
857  date_time_format->time_separator= 0;
858  date_time_format->flag= 0; // For future
859 
860  /*
861  Fill position with 'dummy' arguments to found out if a format tag is
862  used twice (This limit's the format to 255 characters, but this is ok)
863  */
864  dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]=
865  dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= 255;
866 
867  for (; ptr != end; ptr++)
868  {
869  if (*ptr == '%' && ptr+1 != end)
870  {
871  uint position;
872  LINT_INIT(position);
873  switch (*++ptr) {
874  case 'y': // Year
875  case 'Y':
876  position= 0;
877  break;
878  case 'c': // Month
879  case 'm':
880  position= 1;
881  break;
882  case 'd':
883  case 'e':
884  position= 2;
885  break;
886  case 'h':
887  case 'I':
888  case 'l':
889  need_p= 1; // Need AM/PM
890  /* Fall through */
891  case 'k':
892  case 'H':
893  position= 3;
894  break;
895  case 'i':
896  position= 4;
897  break;
898  case 's':
899  case 'S':
900  position= 5;
901  break;
902  case 'f':
903  position= 6;
904  if (dt_pos[5] != offset-1 || ptr[-2] != '.')
905  return 1; // Wrong usage of %f
906  break;
907  case 'p': // AM/PM
908  if (offset == 0) // Can't be first
909  return 0;
910  position= 7;
911  break;
912  default:
913  return 1; // Unknown controll char
914  }
915  if (dt_pos[position] != 255) // Don't allow same tag twice
916  return 1;
917  parts[position]= ptr-1;
918 
919  /*
920  If switching from time to date, ensure that all time parts
921  are used
922  */
923  if (part_map && position <= 2 && !(part_map & (1 | 2 | 4)))
924  offset=5;
925  part_map|= (ulong) 1 << position;
926  dt_pos[position]= offset++;
927  allow_separator= 1;
928  }
929  else
930  {
931  /*
932  Don't allow any characters in format as this could easily confuse
933  the date reader
934  */
935  if (!allow_separator)
936  return 1; // No separator here
937  allow_separator= 0; // Don't allow two separators
938  separators++;
939  /* Store in separator_map which parts are punct characters */
940  if (my_ispunct(&my_charset_latin1, *ptr))
941  separator_map|= (ulong) 1 << (offset-1);
942  else if (!my_isspace(&my_charset_latin1, *ptr))
943  return 1;
944  }
945  }
946 
947  /* If no %f, specify it after seconds. Move %p up, if necessary */
948  if ((part_map & 32) && !(part_map & 64))
949  {
950  dt_pos[6]= dt_pos[5] +1;
951  parts[6]= parts[5]; // For later test in (need_p)
952  if (dt_pos[6] == dt_pos[7]) // Move %p one step up if used
953  dt_pos[7]++;
954  }
955 
956  /*
957  Check that we have not used a non legal format specifier and that all
958  format specifiers have been used
959 
960  The last test is to ensure that %p is used if and only if
961  it's needed.
962  */
963  if ((format_type == MYSQL_TIMESTAMP_DATETIME &&
964  !test_all_bits(part_map, (1 | 2 | 4 | 8 | 16 | 32))) ||
965  (format_type == MYSQL_TIMESTAMP_DATE && part_map != (1 | 2 | 4)) ||
966  (format_type == MYSQL_TIMESTAMP_TIME &&
967  !test_all_bits(part_map, 8 | 16 | 32)) ||
968  !allow_separator || // %option should be last
969  (need_p && dt_pos[6] +1 != dt_pos[7]) ||
970  (need_p ^ (dt_pos[7] != 255)))
971  return 1;
972 
973  if (dt_pos[6] != 255) // If fractional seconds
974  {
975  /* remove fractional seconds from later tests */
976  uint pos= dt_pos[6] -1;
977  /* Remove separator before %f from sep map */
978  separator_map= ((separator_map & ((ulong) (1 << pos)-1)) |
979  ((separator_map & ~((ulong) (1 << pos)-1)) >> 1));
980  if (part_map & 64)
981  {
982  separators--; // There is always a separator
983  need_p= 1; // force use of separators
984  }
985  }
986 
987  /*
988  Remove possible separator before %p from sep_map
989  (This can either be at position 3, 4, 6 or 7) h.m.d.%f %p
990  */
991  if (dt_pos[7] != 255)
992  {
993  if (need_p && parts[7] != parts[6]+2)
994  separators--;
995  }
996  /*
997  Calculate if %p is in first or last part of the datetime field
998 
999  At this point we have either %H-%i-%s %p 'year parts' or
1000  'year parts' &H-%i-%s %p" as %f was removed above
1001  */
1002  offset= dt_pos[6] <= 3 ? 3 : 6;
1003  /* Remove separator before %p from sep map */
1004  separator_map= ((separator_map & ((ulong) (1 << offset)-1)) |
1005  ((separator_map & ~((ulong) (1 << offset)-1)) >> 1));
1006 
1007  format_str= 0;
1008  switch (format_type) {
1009  case MYSQL_TIMESTAMP_DATE:
1010  format_str= known_date_time_formats[INTERNAL_FORMAT].date_format;
1011  /* fall through */
1012  case MYSQL_TIMESTAMP_TIME:
1013  if (!format_str)
1014  format_str=known_date_time_formats[INTERNAL_FORMAT].time_format;
1015 
1016  /*
1017  If there is no separators, allow the internal format as we can read
1018  this. If separators are used, they must be between each part
1019  */
1020  if (format_length == 6 && !need_p &&
1021  !my_strnncoll(&my_charset_bin,
1022  (const uchar *) format, 6,
1023  (const uchar *) format_str, 6))
1024  return 0;
1025  if (separator_map == (1 | 2))
1026  {
1027  if (format_type == MYSQL_TIMESTAMP_TIME)
1028  {
1029  if (*(format+2) != *(format+5))
1030  break; // Error
1031  /* Store the character used for time formats */
1032  date_time_format->time_separator= *(format+2);
1033  }
1034  return 0;
1035  }
1036  break;
1037  case MYSQL_TIMESTAMP_DATETIME:
1038  /*
1039  If there is no separators, allow the internal format as we can read
1040  this. If separators are used, they must be between each part.
1041  Between DATE and TIME we also allow space as separator
1042  */
1043  if ((format_length == 12 && !need_p &&
1044  !my_strnncoll(&my_charset_bin,
1045  (const uchar *) format, 12,
1046  (const uchar*) known_date_time_formats[INTERNAL_FORMAT].datetime_format,
1047  12)) ||
1048  (separators == 5 && separator_map == (1 | 2 | 8 | 16)))
1049  return 0;
1050  break;
1051  default:
1052  DBUG_ASSERT(1);
1053  break;
1054  }
1055  return 1; // Error
1056 }
1057 
1058 
1059 /*
1060  Create a DATE_TIME_FORMAT object from a format string specification
1061 
1062  SYNOPSIS
1063  date_time_format_make()
1064  format_type Format to parse (time, date or datetime)
1065  format_str String to parse
1066  format_length Length of string
1067 
1068  NOTES
1069  The returned object should be freed with my_free()
1070 
1071  RETURN
1072  NULL ponter: Error
1073  new object
1074 */
1075 
1077 *date_time_format_make(timestamp_type format_type,
1078  const char *format_str, uint format_length)
1079 {
1080  DATE_TIME_FORMAT tmp;
1081 
1082  if (format_length && format_length < 255 &&
1083  !parse_date_time_format(format_type, format_str,
1084  format_length, &tmp))
1085  {
1086  tmp.format.str= (char*) format_str;
1087  tmp.format.length= format_length;
1088  return date_time_format_copy((THD *)0, &tmp);
1089  }
1090  return 0;
1091 }
1092 
1093 
1094 /*
1095  Create a copy of a DATE_TIME_FORMAT object
1096 
1097  SYNOPSIS
1098  date_and_time_format_copy()
1099  thd Set if variable should be allocated in thread mem
1100  format format to copy
1101 
1102  NOTES
1103  The returned object should be freed with my_free()
1104 
1105  RETURN
1106  NULL ponter: Error
1107  new object
1108 */
1109 
1110 DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format)
1111 {
1112  DATE_TIME_FORMAT *new_format;
1113  ulong length= sizeof(*format) + format->format.length + 1;
1114 
1115  if (thd)
1116  new_format= (DATE_TIME_FORMAT *) thd->alloc(length);
1117  else
1118  new_format= (DATE_TIME_FORMAT *) my_malloc(length, MYF(MY_WME));
1119  if (new_format)
1120  {
1121  /* Put format string after current pos */
1122  new_format->format.str= (char*) (new_format+1);
1123  memcpy((char*) new_format->positions, (char*) format->positions,
1124  sizeof(format->positions));
1125  new_format->time_separator= format->time_separator;
1126  /* We make the string null terminated for easy printf in SHOW VARIABLES */
1127  memcpy((char*) new_format->format.str, format->format.str,
1128  format->format.length);
1129  new_format->format.str[format->format.length]= 0;
1130  new_format->format.length= format->format.length;
1131  }
1132  return new_format;
1133 }
1134 
1135 
1136 KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]=
1137 {
1138  {"USA", "%m.%d.%Y", "%Y-%m-%d %H.%i.%s", "%h:%i:%s %p" },
1139  {"JIS", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
1140  {"ISO", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
1141  {"EUR", "%d.%m.%Y", "%Y-%m-%d %H.%i.%s", "%H.%i.%s" },
1142  {"INTERNAL", "%Y%m%d", "%Y%m%d%H%i%s", "%H%i%s" },
1143  { 0, 0, 0, 0 }
1144 };
1145 
1146 
1147 /*
1148  Return format string according format name.
1149  If name is unknown, result is NULL
1150 */
1151 
1152 const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
1153  timestamp_type type)
1154 {
1155  switch (type) {
1156  case MYSQL_TIMESTAMP_DATE:
1157  return format->date_format;
1158  case MYSQL_TIMESTAMP_DATETIME:
1159  return format->datetime_format;
1160  case MYSQL_TIMESTAMP_TIME:
1161  return format->time_format;
1162  default:
1163  DBUG_ASSERT(0); // Impossible
1164  return 0;
1165  }
1166 }
1167 
1168 /****************************************************************************
1169  Functions to create default time/date/datetime strings
1170 
1171  NOTE:
1172  For the moment the DATE_TIME_FORMAT argument is ignored becasue
1173  MySQL doesn't support comparing of date/time/datetime strings that
1174  are not in arbutary order as dates are compared as strings in some
1175  context)
1176  This functions don't check that given MYSQL_TIME structure members are
1177  in valid range. If they are not, return value won't reflect any
1178  valid date either. Additionally, make_time doesn't take into
1179  account time->day member: it's assumed that days have been converted
1180  to hours already.
1181 ****************************************************************************/
1182 
1190 void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
1191  const MYSQL_TIME *l_time, String *str, uint dec)
1192 {
1193  uint length= (uint) my_time_to_str(l_time, (char*) str->ptr(), dec);
1194  str->length(length);
1195  str->set_charset(&my_charset_numeric);
1196 }
1197 
1198 
1205 void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
1206  const MYSQL_TIME *l_time, String *str)
1207 {
1208  uint length= (uint) my_date_to_str(l_time, (char*) str->ptr());
1209  str->length(length);
1210  str->set_charset(&my_charset_numeric);
1211 }
1212 
1213 
1221 void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
1222  const MYSQL_TIME *l_time, String *str, uint dec)
1223 {
1224  uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr(), dec);
1225  str->length(length);
1226  str->set_charset(&my_charset_numeric);
1227 }
1228 
1229 
1236 bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec)
1237 {
1238  if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
1239  return true;
1240  str->set_charset(&my_charset_numeric);
1241  str->length(my_TIME_to_str(ltime, const_cast<char*>(str->ptr()), dec));
1242  return false;
1243 }
1244 
1245 
1246 void make_truncated_value_warning(THD *thd,
1247  Sql_condition::enum_warning_level level,
1248  ErrConvString val, timestamp_type time_type,
1249  const char *field_name)
1250 {
1251  char warn_buff[MYSQL_ERRMSG_SIZE];
1252  const char *type_str;
1253  CHARSET_INFO *cs= system_charset_info;
1254 
1255  switch (time_type) {
1256  case MYSQL_TIMESTAMP_DATE:
1257  type_str= "date";
1258  break;
1259  case MYSQL_TIMESTAMP_TIME:
1260  type_str= "time";
1261  break;
1262  case MYSQL_TIMESTAMP_DATETIME: // FALLTHROUGH
1263  default:
1264  type_str= "datetime";
1265  break;
1266  }
1267  if (field_name)
1268  cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
1269  ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
1270  type_str, val.ptr(), field_name,
1271  (ulong) thd->get_stmt_da()->current_row_for_warning());
1272  else
1273  {
1274  if (time_type > MYSQL_TIMESTAMP_ERROR)
1275  cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
1276  ER(ER_TRUNCATED_WRONG_VALUE),
1277  type_str, val.ptr());
1278  else
1279  cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
1280  ER(ER_WRONG_VALUE), type_str, val.ptr());
1281  }
1282  push_warning(thd, level, ER_TRUNCATED_WRONG_VALUE, warn_buff);
1283 }
1284 
1285 
1286 /* Daynumber from year 0 to 9999-12-31 */
1287 #define MAX_DAY_NUMBER 3652424L
1288 
1289 bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval)
1290 {
1291  long period, sign;
1292 
1293  ltime->neg= 0;
1294 
1295  sign= (interval.neg ? -1 : 1);
1296 
1297  switch (int_type) {
1298  case INTERVAL_SECOND:
1299  case INTERVAL_SECOND_MICROSECOND:
1300  case INTERVAL_MICROSECOND:
1301  case INTERVAL_MINUTE:
1302  case INTERVAL_HOUR:
1303  case INTERVAL_MINUTE_MICROSECOND:
1304  case INTERVAL_MINUTE_SECOND:
1305  case INTERVAL_HOUR_MICROSECOND:
1306  case INTERVAL_HOUR_SECOND:
1307  case INTERVAL_HOUR_MINUTE:
1308  case INTERVAL_DAY_MICROSECOND:
1309  case INTERVAL_DAY_SECOND:
1310  case INTERVAL_DAY_MINUTE:
1311  case INTERVAL_DAY_HOUR:
1312  {
1313  longlong sec, days, daynr, microseconds, extra_sec;
1314  ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
1315  microseconds= ltime->second_part + sign*interval.second_part;
1316  extra_sec= microseconds/1000000L;
1317  microseconds= microseconds%1000000L;
1318 
1319  sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
1320  ltime->second +
1321  sign* (longlong) (interval.day*3600*24L +
1322  interval.hour*LL(3600)+interval.minute*LL(60)+
1323  interval.second))+ extra_sec;
1324  if (microseconds < 0)
1325  {
1326  microseconds+= LL(1000000);
1327  sec--;
1328  }
1329  days= sec/(3600*LL(24));
1330  sec-= days*3600*LL(24);
1331  if (sec < 0)
1332  {
1333  days--;
1334  sec+= 3600*LL(24);
1335  }
1336  ltime->second_part= (uint) microseconds;
1337  ltime->second= (uint) (sec % 60);
1338  ltime->minute= (uint) (sec/60 % 60);
1339  ltime->hour= (uint) (sec/3600);
1340  daynr= calc_daynr(ltime->year,ltime->month,1) + days;
1341  /* Day number from year 0 to 9999-12-31 */
1342  if ((ulonglong) daynr > MAX_DAY_NUMBER)
1343  goto invalid_date;
1344  get_date_from_daynr((long) daynr, &ltime->year, &ltime->month,
1345  &ltime->day);
1346  break;
1347  }
1348  case INTERVAL_DAY:
1349  case INTERVAL_WEEK:
1350  period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
1351  sign * (long) interval.day);
1352  /* Daynumber from year 0 to 9999-12-31 */
1353  if ((ulong) period > MAX_DAY_NUMBER)
1354  goto invalid_date;
1355  get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
1356  break;
1357  case INTERVAL_YEAR:
1358  ltime->year+= sign * (long) interval.year;
1359  if ((ulong) ltime->year >= 10000L)
1360  goto invalid_date;
1361  if (ltime->month == 2 && ltime->day == 29 &&
1362  calc_days_in_year(ltime->year) != 366)
1363  ltime->day=28; // Was leap-year
1364  break;
1365  case INTERVAL_YEAR_MONTH:
1366  case INTERVAL_QUARTER:
1367  case INTERVAL_MONTH:
1368  period= (ltime->year*12 + sign * (long) interval.year*12 +
1369  ltime->month-1 + sign * (long) interval.month);
1370  if ((ulong) period >= 120000L)
1371  goto invalid_date;
1372  ltime->year= (uint) (period / 12);
1373  ltime->month= (uint) (period % 12L)+1;
1374  /* Adjust day if the new month doesn't have enough days */
1375  if (ltime->day > days_in_month[ltime->month-1])
1376  {
1377  ltime->day = days_in_month[ltime->month-1];
1378  if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
1379  ltime->day++; // Leap-year
1380  }
1381  break;
1382  default:
1383  goto null_date;
1384  }
1385 
1386  return 0; // Ok
1387 
1388 invalid_date:
1389  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
1390  ER_DATETIME_FUNCTION_OVERFLOW,
1391  ER(ER_DATETIME_FUNCTION_OVERFLOW),
1392  "datetime");
1393 null_date:
1394  return 1;
1395 }
1396 
1397 
1398 /*
1399  Calculate difference between two datetime values as seconds + microseconds.
1400 
1401  SYNOPSIS
1402  calc_time_diff()
1403  l_time1 - TIME/DATE/DATETIME value
1404  l_time2 - TIME/DATE/DATETIME value
1405  l_sign - 1 absolute values are substracted,
1406  -1 absolute values are added.
1407  seconds_out - Out parameter where difference between
1408  l_time1 and l_time2 in seconds is stored.
1409  microseconds_out- Out parameter where microsecond part of difference
1410  between l_time1 and l_time2 is stored.
1411 
1412  NOTE
1413  This function calculates difference between l_time1 and l_time2 absolute
1414  values. So one should set l_sign and correct result if he want to take
1415  signs into account (i.e. for MYSQL_TIME values).
1416 
1417  RETURN VALUES
1418  Returns sign of difference.
1419  1 means negative result
1420  0 means positive result
1421 
1422 */
1423 
1424 bool
1425 calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
1426  int l_sign, longlong *seconds_out, long *microseconds_out)
1427 {
1428  long days;
1429  bool neg;
1430  longlong microseconds;
1431 
1432  /*
1433  We suppose that if first argument is MYSQL_TIMESTAMP_TIME
1434  the second argument should be TIMESTAMP_TIME also.
1435  We should check it before calc_time_diff call.
1436  */
1437  if (l_time1->time_type == MYSQL_TIMESTAMP_TIME) // Time value
1438  days= (long)l_time1->day - l_sign * (long)l_time2->day;
1439  else
1440  {
1441  days= calc_daynr((uint) l_time1->year,
1442  (uint) l_time1->month,
1443  (uint) l_time1->day);
1444  if (l_time2->time_type == MYSQL_TIMESTAMP_TIME)
1445  days-= l_sign * (long)l_time2->day;
1446  else
1447  days-= l_sign*calc_daynr((uint) l_time2->year,
1448  (uint) l_time2->month,
1449  (uint) l_time2->day);
1450  }
1451 
1452  microseconds= ((longlong)days * SECONDS_IN_24H +
1453  (longlong)(l_time1->hour*3600L +
1454  l_time1->minute*60L +
1455  l_time1->second) -
1456  l_sign*(longlong)(l_time2->hour*3600L +
1457  l_time2->minute*60L +
1458  l_time2->second)) * LL(1000000) +
1459  (longlong)l_time1->second_part -
1460  l_sign*(longlong)l_time2->second_part;
1461 
1462  neg= 0;
1463  if (microseconds < 0)
1464  {
1465  microseconds= -microseconds;
1466  neg= 1;
1467  }
1468  *seconds_out= microseconds/1000000L;
1469  *microseconds_out= (long) (microseconds%1000000L);
1470  return neg;
1471 }
1472 
1473 
1474 /*
1475  Compares 2 MYSQL_TIME structures
1476 
1477  SYNOPSIS
1478  my_time_compare()
1479 
1480  a - first time
1481  b - second time
1482 
1483  RETURN VALUE
1484  -1 - a < b
1485  0 - a == b
1486  1 - a > b
1487 
1488 */
1489 
1490 int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b)
1491 {
1492  ulonglong a_t= TIME_to_ulonglong_datetime(a);
1493  ulonglong b_t= TIME_to_ulonglong_datetime(b);
1494 
1495  if (a_t < b_t)
1496  return -1;
1497  if (a_t > b_t)
1498  return 1;
1499 
1500  if (a->second_part < b->second_part)
1501  return -1;
1502  if (a->second_part > b->second_part)
1503  return 1;
1504 
1505  return 0;
1506 }
1507 
1508 
1509 /* Rounding functions */
1510 static uint msec_round_add[7]=
1511 {
1512  500000000,
1513  50000000,
1514  5000000,
1515  500000,
1516  50000,
1517  5000,
1518  0
1519 };
1520 
1521 
1529 bool my_time_round(MYSQL_TIME *ltime, uint dec)
1530 {
1531  int warnings= 0;
1532  DBUG_ASSERT(dec <= DATETIME_MAX_DECIMALS);
1533  /* Add half away from zero */
1534  bool rc= time_add_nanoseconds_with_round(ltime,
1535  msec_round_add[dec], &warnings);
1536  /* Truncate non-significant digits */
1537  my_time_trunc(ltime, dec);
1538  return rc;
1539 }
1540 
1541 
1549 bool my_datetime_round(MYSQL_TIME *ltime, uint dec, int *warnings)
1550 {
1551  DBUG_ASSERT(dec <= DATETIME_MAX_DECIMALS);
1552  /* Add half away from zero */
1553  bool rc= datetime_add_nanoseconds_with_round(ltime,
1554  msec_round_add[dec], warnings);
1555  /* Truncate non-significant digits */
1556  my_time_trunc(ltime, dec);
1557  return rc;
1558 }
1559 
1560 
1568 bool my_timeval_round(struct timeval *tv, uint decimals)
1569 {
1570  DBUG_ASSERT(decimals <= DATETIME_MAX_DECIMALS);
1571  uint nanoseconds= msec_round_add[decimals];
1572  tv->tv_usec+= (nanoseconds + 500) / 1000;
1573  if (tv->tv_usec < 1000000)
1574  goto ret;
1575 
1576  tv->tv_usec= 0;
1577  tv->tv_sec++;
1578  if (!IS_TIME_T_VALID_FOR_TIMESTAMP(tv->tv_sec))
1579  {
1580  tv->tv_sec= TIMESTAMP_MAX_VALUE;
1581  return true;
1582  }
1583 
1584 ret:
1585  my_timeval_trunc(tv, decimals);
1586  return false;
1587 }
1588 
1589 
1596 void mix_date_and_time(MYSQL_TIME *ldate, const MYSQL_TIME *ltime)
1597 {
1598  DBUG_ASSERT(ldate->time_type == MYSQL_TIMESTAMP_DATE ||
1599  ldate->time_type == MYSQL_TIMESTAMP_DATETIME);
1600 
1601  if (!ltime->neg && ltime->hour < 24)
1602  {
1603  /*
1604  Simple case: TIME is within normal 24 hours internal.
1605  Mix DATE part of ltime2 and TIME part of ltime together.
1606  */
1607  ldate->hour= ltime->hour;
1608  ldate->minute= ltime->minute;
1609  ldate->second= ltime->second;
1610  ldate->second_part= ltime->second_part;
1611  }
1612  else
1613  {
1614  /* Complex case: TIME is negative or outside of 24 hours internal. */
1615  longlong seconds;
1616  long days, useconds;
1617  int sign= ltime->neg ? 1 : -1;
1618  ldate->neg= calc_time_diff(ldate, ltime, sign, &seconds, &useconds);
1619  DBUG_ASSERT(!ldate->neg);
1620 
1621  /*
1622  We pass current date to mix_date_and_time. If we want to use
1623  this function with arbitrary dates, this code will need
1624  to cover cases when ltime is negative and "ldate < -ltime".
1625  */
1626  DBUG_ASSERT(ldate->year > 0);
1627 
1628  days= (long) (seconds / SECONDS_IN_24H);
1629  calc_time_from_sec(ldate, seconds % SECONDS_IN_24H, useconds);
1630  get_date_from_daynr(days, &ldate->year, &ldate->month, &ldate->day);
1631  }
1632  ldate->time_type= MYSQL_TIMESTAMP_DATETIME;
1633 }
1634 
1635 
1643 longlong TIME_to_longlong_packed(const MYSQL_TIME *ltime,
1644  enum enum_field_types type)
1645 {
1646  switch (type)
1647  {
1648  case MYSQL_TYPE_TIME:
1649  return TIME_to_longlong_time_packed(ltime);
1650  case MYSQL_TYPE_DATETIME:
1651  case MYSQL_TYPE_TIMESTAMP:
1652  return TIME_to_longlong_datetime_packed(ltime);
1653  case MYSQL_TYPE_DATE:
1654  return TIME_to_longlong_date_packed(ltime);
1655  default:
1656  return TIME_to_longlong_packed(ltime);
1657  }
1658 }
1659 
1660 
1668 void TIME_from_longlong_packed(MYSQL_TIME *ltime,
1669  enum enum_field_types type,
1670  longlong packed_value)
1671 {
1672  switch (type)
1673  {
1674  case MYSQL_TYPE_TIME:
1675  TIME_from_longlong_time_packed(ltime, packed_value);
1676  break;
1677  case MYSQL_TYPE_DATE:
1678  TIME_from_longlong_date_packed(ltime, packed_value);
1679  break;
1680  case MYSQL_TYPE_DATETIME:
1681  case MYSQL_TYPE_TIMESTAMP:
1682  TIME_from_longlong_datetime_packed(ltime, packed_value);
1683  break;
1684  default:
1685  DBUG_ASSERT(0);
1686  set_zero_time(ltime, MYSQL_TIMESTAMP_ERROR);
1687  break;
1688  }
1689 }
1690 
1691 
1702 my_decimal *my_decimal_from_datetime_packed(my_decimal *dec,
1703  enum enum_field_types type,
1704  longlong packed_value)
1705 {
1706  MYSQL_TIME ltime;
1707  switch (type)
1708  {
1709  case MYSQL_TYPE_TIME:
1710  TIME_from_longlong_time_packed(&ltime, packed_value);
1711  return time2my_decimal(&ltime, dec);
1712  case MYSQL_TYPE_DATE:
1713  TIME_from_longlong_date_packed(&ltime, packed_value);
1714  ulonglong2decimal(TIME_to_ulonglong_date(&ltime), dec);
1715  return dec;
1716  case MYSQL_TYPE_DATETIME:
1717  case MYSQL_TYPE_TIMESTAMP:
1718  TIME_from_longlong_datetime_packed(&ltime, packed_value);
1719  return date2my_decimal(&ltime, dec);
1720  default:
1721  DBUG_ASSERT(0);
1722  ulonglong2decimal(0, dec);
1723  return dec;
1724  }
1725 }
1726 
1727 
1736 longlong longlong_from_datetime_packed(enum enum_field_types type,
1737  longlong packed_value)
1738 {
1739  MYSQL_TIME ltime;
1740  switch (type)
1741  {
1742  case MYSQL_TYPE_TIME:
1743  TIME_from_longlong_time_packed(&ltime, packed_value);
1744  return TIME_to_ulonglong_time(&ltime);
1745  case MYSQL_TYPE_DATE:
1746  TIME_from_longlong_date_packed(&ltime, packed_value);
1747  return TIME_to_ulonglong_date(&ltime);
1748  case MYSQL_TYPE_DATETIME:
1749  case MYSQL_TYPE_TIMESTAMP:
1750  TIME_from_longlong_datetime_packed(&ltime, packed_value);
1751  return TIME_to_ulonglong_datetime(&ltime);
1752  default:
1753  DBUG_ASSERT(0);
1754  return 0;
1755  }
1756 }
1757 
1758 
1768 double double_from_datetime_packed(enum enum_field_types type,
1769  longlong packed_value)
1770 {
1771  longlong result= longlong_from_datetime_packed(type, packed_value);
1772  return result +
1773  ((double) MY_PACKED_TIME_GET_FRAC_PART(packed_value)) / 1000000;
1774 }
1775 
1776 #endif