1
/* Copyright (C) 2000-2006 MySQL AB
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
/* Functions to handle date and time */
19
#include "mysql_priv.h"
23
/* Some functions to calculate dates */
28
Name description of interval names used in statements.
30
'interval_type_to_name' is ordered and sorted on interval size and
32
Order of elements in 'interval_type_to_name' should correspond to
33
the order of elements in 'interval_type' enum
35
See also interval_type, interval_names
38
LEX_STRING interval_type_to_name[INTERVAL_LAST] = {
39
{ C_STRING_WITH_LEN("YEAR")},
40
{ C_STRING_WITH_LEN("QUARTER")},
41
{ C_STRING_WITH_LEN("MONTH")},
42
{ C_STRING_WITH_LEN("WEEK")},
43
{ C_STRING_WITH_LEN("DAY")},
44
{ C_STRING_WITH_LEN("HOUR")},
45
{ C_STRING_WITH_LEN("MINUTE")},
46
{ C_STRING_WITH_LEN("SECOND")},
47
{ C_STRING_WITH_LEN("MICROSECOND")},
48
{ C_STRING_WITH_LEN("YEAR_MONTH")},
49
{ C_STRING_WITH_LEN("DAY_HOUR")},
50
{ C_STRING_WITH_LEN("DAY_MINUTE")},
51
{ C_STRING_WITH_LEN("DAY_SECOND")},
52
{ C_STRING_WITH_LEN("HOUR_MINUTE")},
53
{ C_STRING_WITH_LEN("HOUR_SECOND")},
54
{ C_STRING_WITH_LEN("MINUTE_SECOND")},
55
{ C_STRING_WITH_LEN("DAY_MICROSECOND")},
56
{ C_STRING_WITH_LEN("HOUR_MICROSECOND")},
57
{ C_STRING_WITH_LEN("MINUTE_MICROSECOND")},
58
{ C_STRING_WITH_LEN("SECOND_MICROSECOND")}
61
/* Calc weekday from daynr */
62
/* Returns 0 for monday, 1 for tuesday .... */
64
int calc_weekday(long daynr,bool sunday_first_day_of_week)
66
DBUG_ENTER("calc_weekday");
67
DBUG_RETURN ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
71
The bits in week_format has the following meaning:
72
WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week
73
If set Monday is first day of week
74
WEEK_YEAR (1) If not set Week is in range 0-53
76
Week 0 is returned for the the last week of the previous year (for
77
a date at start of january) In this case one can get 53 for the
78
first week of next year. This flag ensures that the week is
79
relevant for the given year. Note that this flag is only
80
releveant if WEEK_JANUARY is not set.
82
If set Week is in range 1-53.
84
In this case one may get week 53 for a date in January (when
85
the week is that last week of previous year) and week 1 for a
88
WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according
90
If set The week that contains the first
91
'first-day-of-week' is week 1.
93
ISO 8601:1988 means that if the week containing January 1 has
94
four or more days in the new year, then it is week 1;
95
Otherwise it is the last week of the previous year, and the
99
uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year)
102
ulong daynr=calc_daynr(l_time->year,l_time->month,l_time->day);
103
ulong first_daynr=calc_daynr(l_time->year,1,1);
104
bool monday_first= test(week_behaviour & WEEK_MONDAY_FIRST);
105
bool week_year= test(week_behaviour & WEEK_YEAR);
106
bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
108
uint weekday=calc_weekday(first_daynr, !monday_first);
111
if (l_time->month == 1 && l_time->day <= 7-weekday)
114
((first_weekday && weekday != 0) ||
115
(!first_weekday && weekday >= 4)))
119
first_daynr-= (days=calc_days_in_year(*year));
120
weekday= (weekday + 53*7- days) % 7;
123
if ((first_weekday && weekday != 0) ||
124
(!first_weekday && weekday >= 4))
125
days= daynr - (first_daynr+ (7-weekday));
127
days= daynr - (first_daynr - weekday);
129
if (week_year && days >= 52*7)
131
weekday= (weekday + calc_days_in_year(*year)) % 7;
132
if ((!first_weekday && weekday < 4) ||
133
(first_weekday && weekday == 0))
142
/* Change a daynr to year, month and day */
143
/* Daynr 0 is returned as date 00.00.00 */
145
void get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month,
148
uint year,temp,leap_day,day_of_year,days_in_year;
150
DBUG_ENTER("get_date_from_daynr");
152
if (daynr <= 365L || daynr >= 3652500)
153
{ /* Fix if wrong daynr */
154
*ret_year= *ret_month = *ret_day =0;
158
year= (uint) (daynr*100 / 36525L);
159
temp=(((year-1)/100+1)*3)/4;
160
day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp;
161
while (day_of_year > (days_in_year= calc_days_in_year(year)))
163
day_of_year-=days_in_year;
167
if (days_in_year == 366)
169
if (day_of_year > 31+28)
172
if (day_of_year == 31+28)
173
leap_day=1; /* Handle leapyears leapday */
177
for (month_pos= days_in_month ;
178
day_of_year > (uint) *month_pos ;
179
day_of_year-= *(month_pos++), (*ret_month)++)
182
*ret_day=day_of_year+leap_day;
187
/* Functions to handle periods */
189
ulong convert_period_to_month(ulong period)
194
if ((a=period/100) < YY_PART_YEAR)
203
ulong convert_month_to_period(ulong month)
208
if ((year=month/12) < 100)
210
year+=(year < YY_PART_YEAR) ? 2000 : 1900;
212
return year*100+month%12+1;
217
Convert a timestamp string to a MYSQL_TIME value and produce a warning
218
if string was truncated during conversion.
221
See description of str_to_datetime() for more information.
225
str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
229
THD *thd= current_thd;
230
timestamp_type ts_type;
232
ts_type= str_to_datetime(str, length, l_time,
233
(flags | (thd->variables.sql_mode &
234
(MODE_INVALID_DATES |
235
MODE_NO_ZERO_DATE))),
237
if (was_cut || ts_type <= MYSQL_TIMESTAMP_ERROR)
238
make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
239
str, length, ts_type, NullS);
245
Convert a datetime from broken-down MYSQL_TIME representation to corresponding
251
t - datetime in broken-down representation,
252
in_dst_time_gap - pointer to bool which is set to true if t represents
253
value which doesn't exists (falls into the spring
254
time-gap) or to false otherwise.
257
Number seconds in UTC since start of Unix Epoch corresponding to t.
258
0 - t contains datetime value which is out of TIMESTAMP range.
261
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *in_dst_time_gap)
266
thd->time_zone_used= 1;
268
timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap);
274
/* If we are here we have range error. */
280
Convert a time string to a MYSQL_TIME struct and produce a warning
281
if string was cut during conversion.
284
See str_to_time() for more info.
287
str_to_time_with_warn(const char *str, uint length, MYSQL_TIME *l_time)
290
bool ret_val= str_to_time(str, length, l_time, &warning);
291
if (ret_val || warning)
292
make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
293
str, length, MYSQL_TIMESTAMP_TIME, NullS);
299
Convert a system time structure to TIME
302
void localtime_to_TIME(MYSQL_TIME *to, struct tm *from)
306
to->year= (int) ((from->tm_year+1900) % 10000);
307
to->month= (int) from->tm_mon+1;
308
to->day= (int) from->tm_mday;
309
to->hour= (int) from->tm_hour;
310
to->minute= (int) from->tm_min;
311
to->second= (int) from->tm_sec;
314
void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds)
317
// to->neg is not cleared, it may already be set to a useful value
318
to->time_type= MYSQL_TIMESTAMP_TIME;
322
to->hour= seconds/3600L;
323
t_seconds= seconds%3600L;
324
to->minute= t_seconds/60L;
325
to->second= t_seconds%60L;
326
to->second_part= microseconds;
331
Parse a format string specification
334
parse_date_time_format()
335
format_type Format of string (time, date or datetime)
336
format_str String to parse
337
format_length Length of string
338
date_time_format Format to fill in
341
Fills in date_time_format->positions for all date time parts.
343
positions marks the position for a datetime element in the format string.
344
The position array elements are in the following order:
345
YYYY-DD-MM HH-MM-DD.FFFFFF AM
348
If positions[0]= 5, it means that year will be the forth element to
349
read from the parsed date string.
356
bool parse_date_time_format(timestamp_type format_type,
357
const char *format, uint format_length,
358
DATE_TIME_FORMAT *date_time_format)
360
uint offset= 0, separators= 0;
361
const char *ptr= format, *format_str;
362
const char *end= ptr+format_length;
363
uchar *dt_pos= date_time_format->positions;
364
/* need_p is set if we are using AM/PM format */
365
bool need_p= 0, allow_separator= 0;
366
ulong part_map= 0, separator_map= 0;
367
const char *parts[16];
369
date_time_format->time_separator= 0;
370
date_time_format->flag= 0; // For future
373
Fill position with 'dummy' arguments to found out if a format tag is
374
used twice (This limit's the format to 255 characters, but this is ok)
376
dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]=
377
dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= 255;
379
for (; ptr != end; ptr++)
381
if (*ptr == '%' && ptr+1 != end)
401
need_p= 1; // Need AM/PM
416
if (dt_pos[5] != offset-1 || ptr[-2] != '.')
417
return 1; // Wrong usage of %f
420
if (offset == 0) // Can't be first
425
return 1; // Unknown controll char
427
if (dt_pos[position] != 255) // Don't allow same tag twice
429
parts[position]= ptr-1;
432
If switching from time to date, ensure that all time parts
435
if (part_map && position <= 2 && !(part_map & (1 | 2 | 4)))
437
part_map|= (ulong) 1 << position;
438
dt_pos[position]= offset++;
444
Don't allow any characters in format as this could easily confuse
447
if (!allow_separator)
448
return 1; // No separator here
449
allow_separator= 0; // Don't allow two separators
451
/* Store in separator_map which parts are punct characters */
452
if (my_ispunct(&my_charset_latin1, *ptr))
453
separator_map|= (ulong) 1 << (offset-1);
454
else if (!my_isspace(&my_charset_latin1, *ptr))
459
/* If no %f, specify it after seconds. Move %p up, if necessary */
460
if ((part_map & 32) && !(part_map & 64))
462
dt_pos[6]= dt_pos[5] +1;
463
parts[6]= parts[5]; // For later test in (need_p)
464
if (dt_pos[6] == dt_pos[7]) // Move %p one step up if used
469
Check that we have not used a non legal format specifier and that all
470
format specifiers have been used
472
The last test is to ensure that %p is used if and only if
475
if ((format_type == MYSQL_TIMESTAMP_DATETIME &&
476
!test_all_bits(part_map, (1 | 2 | 4 | 8 | 16 | 32))) ||
477
(format_type == MYSQL_TIMESTAMP_DATE && part_map != (1 | 2 | 4)) ||
478
(format_type == MYSQL_TIMESTAMP_TIME &&
479
!test_all_bits(part_map, 8 | 16 | 32)) ||
480
!allow_separator || // %option should be last
481
(need_p && dt_pos[6] +1 != dt_pos[7]) ||
482
(need_p ^ (dt_pos[7] != 255)))
485
if (dt_pos[6] != 255) // If fractional seconds
487
/* remove fractional seconds from later tests */
488
uint pos= dt_pos[6] -1;
489
/* Remove separator before %f from sep map */
490
separator_map= ((separator_map & ((ulong) (1 << pos)-1)) |
491
((separator_map & ~((ulong) (1 << pos)-1)) >> 1));
494
separators--; // There is always a separator
495
need_p= 1; // force use of separators
500
Remove possible separator before %p from sep_map
501
(This can either be at position 3, 4, 6 or 7) h.m.d.%f %p
503
if (dt_pos[7] != 255)
505
if (need_p && parts[7] != parts[6]+2)
509
Calculate if %p is in first or last part of the datetime field
511
At this point we have either %H-%i-%s %p 'year parts' or
512
'year parts' &H-%i-%s %p" as %f was removed above
514
offset= dt_pos[6] <= 3 ? 3 : 6;
515
/* Remove separator before %p from sep map */
516
separator_map= ((separator_map & ((ulong) (1 << offset)-1)) |
517
((separator_map & ~((ulong) (1 << offset)-1)) >> 1));
520
switch (format_type) {
521
case MYSQL_TIMESTAMP_DATE:
522
format_str= known_date_time_formats[INTERNAL_FORMAT].date_format;
524
case MYSQL_TIMESTAMP_TIME:
526
format_str=known_date_time_formats[INTERNAL_FORMAT].time_format;
529
If there is no separators, allow the internal format as we can read
530
this. If separators are used, they must be between each part
532
if (format_length == 6 && !need_p &&
533
!my_strnncoll(&my_charset_bin,
534
(const uchar *) format, 6,
535
(const uchar *) format_str, 6))
537
if (separator_map == (1 | 2))
539
if (format_type == MYSQL_TIMESTAMP_TIME)
541
if (*(format+2) != *(format+5))
543
/* Store the character used for time formats */
544
date_time_format->time_separator= *(format+2);
549
case MYSQL_TIMESTAMP_DATETIME:
551
If there is no separators, allow the internal format as we can read
552
this. If separators are used, they must be between each part.
553
Between DATE and TIME we also allow space as separator
555
if ((format_length == 12 && !need_p &&
556
!my_strnncoll(&my_charset_bin,
557
(const uchar *) format, 12,
558
(const uchar*) known_date_time_formats[INTERNAL_FORMAT].datetime_format,
560
(separators == 5 && separator_map == (1 | 2 | 8 | 16)))
572
Create a DATE_TIME_FORMAT object from a format string specification
575
date_time_format_make()
576
format_type Format to parse (time, date or datetime)
577
format_str String to parse
578
format_length Length of string
581
The returned object should be freed with my_free()
589
*date_time_format_make(timestamp_type format_type,
590
const char *format_str, uint format_length)
592
DATE_TIME_FORMAT tmp;
594
if (format_length && format_length < 255 &&
595
!parse_date_time_format(format_type, format_str,
596
format_length, &tmp))
598
tmp.format.str= (char*) format_str;
599
tmp.format.length= format_length;
600
return date_time_format_copy((THD *)0, &tmp);
607
Create a copy of a DATE_TIME_FORMAT object
610
date_and_time_format_copy()
611
thd Set if variable should be allocated in thread mem
612
format format to copy
615
The returned object should be freed with my_free()
622
DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format)
624
DATE_TIME_FORMAT *new_format;
625
ulong length= sizeof(*format) + format->format.length + 1;
628
new_format= (DATE_TIME_FORMAT *) thd->alloc(length);
630
new_format= (DATE_TIME_FORMAT *) my_malloc(length, MYF(MY_WME));
633
/* Put format string after current pos */
634
new_format->format.str= (char*) (new_format+1);
635
memcpy((char*) new_format->positions, (char*) format->positions,
636
sizeof(format->positions));
637
new_format->time_separator= format->time_separator;
638
/* We make the string null terminated for easy printf in SHOW VARIABLES */
639
memcpy((char*) new_format->format.str, format->format.str,
640
format->format.length);
641
new_format->format.str[format->format.length]= 0;
642
new_format->format.length= format->format.length;
648
KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]=
650
{"USA", "%m.%d.%Y", "%Y-%m-%d %H.%i.%s", "%h:%i:%s %p" },
651
{"JIS", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
652
{"ISO", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
653
{"EUR", "%d.%m.%Y", "%Y-%m-%d %H.%i.%s", "%H.%i.%s" },
654
{"INTERNAL", "%Y%m%d", "%Y%m%d%H%i%s", "%H%i%s" },
660
Return format string according format name.
661
If name is unknown, result is NULL
664
const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
668
case MYSQL_TIMESTAMP_DATE:
669
return format->date_format;
670
case MYSQL_TIMESTAMP_DATETIME:
671
return format->datetime_format;
672
case MYSQL_TIMESTAMP_TIME:
673
return format->time_format;
675
DBUG_ASSERT(0); // Impossible
680
/****************************************************************************
681
Functions to create default time/date/datetime strings
684
For the moment the DATE_TIME_FORMAT argument is ignored becasue
685
MySQL doesn't support comparing of date/time/datetime strings that
686
are not in arbutary order as dates are compared as strings in some
688
This functions don't check that given MYSQL_TIME structure members are
689
in valid range. If they are not, return value won't reflect any
690
valid date either. Additionally, make_time doesn't take into
691
account time->day member: it's assumed that days have been converted
693
****************************************************************************/
695
void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
696
const MYSQL_TIME *l_time, String *str)
698
uint length= (uint) my_time_to_str(l_time, (char*) str->ptr());
700
str->set_charset(&my_charset_bin);
704
void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
705
const MYSQL_TIME *l_time, String *str)
707
uint length= (uint) my_date_to_str(l_time, (char*) str->ptr());
709
str->set_charset(&my_charset_bin);
713
void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
714
const MYSQL_TIME *l_time, String *str)
716
uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr());
718
str->set_charset(&my_charset_bin);
722
void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
724
uint str_length, timestamp_type time_type,
725
const char *field_name)
727
char warn_buff[MYSQL_ERRMSG_SIZE];
728
const char *type_str;
729
CHARSET_INFO *cs= &my_charset_latin1;
731
String str(buff,(uint32) sizeof(buff), system_charset_info);
732
str.copy(str_val, str_length, system_charset_info);
733
str[str_length]= 0; // Ensure we have end 0 for snprintf
736
case MYSQL_TIMESTAMP_DATE:
739
case MYSQL_TIMESTAMP_TIME:
742
case MYSQL_TIMESTAMP_DATETIME: // FALLTHROUGH
744
type_str= "datetime";
748
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
749
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
750
type_str, str.c_ptr(), field_name,
751
(ulong) thd->row_count);
754
if (time_type > MYSQL_TIMESTAMP_ERROR)
755
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
756
ER(ER_TRUNCATED_WRONG_VALUE),
757
type_str, str.c_ptr());
759
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
760
ER(ER_WRONG_VALUE), type_str, str.c_ptr());
762
push_warning(thd, level,
763
ER_TRUNCATED_WRONG_VALUE, warn_buff);
766
/* Daynumber from year 0 to 9999-12-31 */
767
#define MAX_DAY_NUMBER 3652424L
769
bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval)
775
sign= (interval.neg ? -1 : 1);
778
case INTERVAL_SECOND:
779
case INTERVAL_SECOND_MICROSECOND:
780
case INTERVAL_MICROSECOND:
781
case INTERVAL_MINUTE:
783
case INTERVAL_MINUTE_MICROSECOND:
784
case INTERVAL_MINUTE_SECOND:
785
case INTERVAL_HOUR_MICROSECOND:
786
case INTERVAL_HOUR_SECOND:
787
case INTERVAL_HOUR_MINUTE:
788
case INTERVAL_DAY_MICROSECOND:
789
case INTERVAL_DAY_SECOND:
790
case INTERVAL_DAY_MINUTE:
791
case INTERVAL_DAY_HOUR:
793
longlong sec, days, daynr, microseconds, extra_sec;
794
ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
795
microseconds= ltime->second_part + sign*interval.second_part;
796
extra_sec= microseconds/1000000L;
797
microseconds= microseconds%1000000L;
799
sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
801
sign* (longlong) (interval.day*3600*24L +
802
interval.hour*LL(3600)+interval.minute*LL(60)+
803
interval.second))+ extra_sec;
804
if (microseconds < 0)
806
microseconds+= LL(1000000);
809
days= sec/(3600*LL(24));
810
sec-= days*3600*LL(24);
816
ltime->second_part= (uint) microseconds;
817
ltime->second= (uint) (sec % 60);
818
ltime->minute= (uint) (sec/60 % 60);
819
ltime->hour= (uint) (sec/3600);
820
daynr= calc_daynr(ltime->year,ltime->month,1) + days;
821
/* Day number from year 0 to 9999-12-31 */
822
if ((ulonglong) daynr > MAX_DAY_NUMBER)
824
get_date_from_daynr((long) daynr, <ime->year, <ime->month,
830
period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
831
sign * (long) interval.day);
832
/* Daynumber from year 0 to 9999-12-31 */
833
if ((ulong) period > MAX_DAY_NUMBER)
835
get_date_from_daynr((long) period,<ime->year,<ime->month,<ime->day);
838
ltime->year+= sign * (long) interval.year;
839
if ((ulong) ltime->year >= 10000L)
841
if (ltime->month == 2 && ltime->day == 29 &&
842
calc_days_in_year(ltime->year) != 366)
843
ltime->day=28; // Was leap-year
845
case INTERVAL_YEAR_MONTH:
846
case INTERVAL_QUARTER:
848
period= (ltime->year*12 + sign * (long) interval.year*12 +
849
ltime->month-1 + sign * (long) interval.month);
850
if ((ulong) period >= 120000L)
852
ltime->year= (uint) (period / 12);
853
ltime->month= (uint) (period % 12L)+1;
854
/* Adjust day if the new month doesn't have enough days */
855
if (ltime->day > days_in_month[ltime->month-1])
857
ltime->day = days_in_month[ltime->month-1];
858
if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
859
ltime->day++; // Leap-year
869
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
870
ER_DATETIME_FUNCTION_OVERFLOW,
871
ER(ER_DATETIME_FUNCTION_OVERFLOW),
879
Calculate difference between two datetime values as seconds + microseconds.
883
l_time1 - TIME/DATE/DATETIME value
884
l_time2 - TIME/DATE/DATETIME value
885
l_sign - 1 absolute values are substracted,
886
-1 absolute values are added.
887
seconds_out - Out parameter where difference between
888
l_time1 and l_time2 in seconds is stored.
889
microseconds_out- Out parameter where microsecond part of difference
890
between l_time1 and l_time2 is stored.
893
This function calculates difference between l_time1 and l_time2 absolute
894
values. So one should set l_sign and correct result if he want to take
895
signs into account (i.e. for MYSQL_TIME values).
898
Returns sign of difference.
899
1 means negative result
900
0 means positive result
905
calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign, longlong *seconds_out,
906
long *microseconds_out)
910
longlong microseconds;
913
We suppose that if first argument is MYSQL_TIMESTAMP_TIME
914
the second argument should be TIMESTAMP_TIME also.
915
We should check it before calc_time_diff call.
917
if (l_time1->time_type == MYSQL_TIMESTAMP_TIME) // Time value
918
days= (long)l_time1->day - l_sign * (long)l_time2->day;
921
days= calc_daynr((uint) l_time1->year,
922
(uint) l_time1->month,
923
(uint) l_time1->day);
924
if (l_time2->time_type == MYSQL_TIMESTAMP_TIME)
925
days-= l_sign * (long)l_time2->day;
927
days-= l_sign*calc_daynr((uint) l_time2->year,
928
(uint) l_time2->month,
929
(uint) l_time2->day);
932
microseconds= ((longlong)days*LL(86400) +
933
(longlong)(l_time1->hour*3600L +
934
l_time1->minute*60L +
936
l_sign*(longlong)(l_time2->hour*3600L +
937
l_time2->minute*60L +
938
l_time2->second)) * LL(1000000) +
939
(longlong)l_time1->second_part -
940
l_sign*(longlong)l_time2->second_part;
943
if (microseconds < 0)
945
microseconds= -microseconds;
948
*seconds_out= microseconds/1000000L;
949
*microseconds_out= (long) (microseconds%1000000L);
955
Compares 2 MYSQL_TIME structures
970
int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b)
972
ulonglong a_t= TIME_to_ulonglong_datetime(a);
973
ulonglong b_t= TIME_to_ulonglong_datetime(b);
980
if (a->second_part < b->second_part)
982
if (a->second_part > b->second_part)