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)
113
if ((!week_year) && ((first_weekday && weekday != 0) || (!first_weekday && weekday >= 4)))
117
first_daynr-= (days=calc_days_in_year(*year));
118
weekday= (weekday + 53*7- days) % 7;
121
if ((first_weekday && weekday != 0) ||
122
(!first_weekday && weekday >= 4))
123
days= daynr - (first_daynr+ (7-weekday));
125
days= daynr - (first_daynr - weekday);
127
if (week_year && days >= 52*7)
129
weekday= (weekday + calc_days_in_year(*year)) % 7;
130
if ((!first_weekday && weekday < 4) || (first_weekday && weekday == 0))
139
/* Change a daynr to year, month and day */
140
/* Daynr 0 is returned as date 00.00.00 */
142
void get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month,
145
uint year,temp,leap_day,day_of_year,days_in_year;
147
DBUG_ENTER("get_date_from_daynr");
149
if (daynr <= 365L || daynr >= 3652500)
150
{ /* Fix if wrong daynr */
151
*ret_year= *ret_month = *ret_day =0;
155
year= (uint) (daynr*100 / 36525L);
156
temp=(((year-1)/100+1)*3)/4;
157
day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp;
158
while (day_of_year > (days_in_year= calc_days_in_year(year)))
160
day_of_year-=days_in_year;
164
if (days_in_year == 366)
166
if (day_of_year > 31+28)
169
if (day_of_year == 31+28)
170
leap_day=1; /* Handle leapyears leapday */
174
for (month_pos= days_in_month ;
175
day_of_year > (uint) *month_pos ;
176
day_of_year-= *(month_pos++), (*ret_month)++)
179
*ret_day=day_of_year+leap_day;
184
/* Functions to handle periods */
186
ulong convert_period_to_month(ulong period)
191
if ((a=period/100) < YY_PART_YEAR)
200
ulong convert_month_to_period(ulong month)
205
if ((year=month/12) < 100)
207
year+=(year < YY_PART_YEAR) ? 2000 : 1900;
209
return year*100+month%12+1;
214
Convert a timestamp string to a MYSQL_TIME value and produce a warning
215
if string was truncated during conversion.
218
See description of str_to_datetime() for more information.
222
str_to_datetime_with_warn(const char *str, uint length, MYSQL_TIME *l_time,
226
THD *thd= current_thd;
227
timestamp_type ts_type;
229
ts_type= str_to_datetime(str, length, l_time,
230
(flags | (thd->variables.sql_mode &
231
(MODE_INVALID_DATES |
232
MODE_NO_ZERO_DATE))),
234
if (was_cut || ts_type <= MYSQL_TIMESTAMP_ERROR)
235
make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
236
str, length, ts_type, NullS);
242
Convert a datetime from broken-down MYSQL_TIME representation to corresponding
248
t - datetime in broken-down representation,
249
in_dst_time_gap - pointer to bool which is set to true if t represents
250
value which doesn't exists (falls into the spring
251
time-gap) or to false otherwise.
254
Number seconds in UTC since start of Unix Epoch corresponding to t.
255
0 - t contains datetime value which is out of TIMESTAMP range.
258
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *in_dst_time_gap)
263
thd->time_zone_used= 1;
265
timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap);
271
/* If we are here we have range error. */
277
Convert a time string to a MYSQL_TIME struct and produce a warning
278
if string was cut during conversion.
281
See str_to_time() for more info.
284
str_to_time_with_warn(const char *str, uint length, MYSQL_TIME *l_time)
287
bool ret_val= str_to_time(str, length, l_time, &warning);
288
if (ret_val || warning)
289
make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
290
str, length, MYSQL_TIMESTAMP_TIME, NullS);
296
Convert a system time structure to TIME
299
void localtime_to_TIME(MYSQL_TIME *to, struct tm *from)
303
to->year= (int) ((from->tm_year+1900) % 10000);
304
to->month= (int) from->tm_mon+1;
305
to->day= (int) from->tm_mday;
306
to->hour= (int) from->tm_hour;
307
to->minute= (int) from->tm_min;
308
to->second= (int) from->tm_sec;
311
void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds)
314
// to->neg is not cleared, it may already be set to a useful value
315
to->time_type= MYSQL_TIMESTAMP_TIME;
319
to->hour= seconds/3600L;
320
t_seconds= seconds%3600L;
321
to->minute= t_seconds/60L;
322
to->second= t_seconds%60L;
323
to->second_part= microseconds;
328
Parse a format string specification
331
parse_date_time_format()
332
format_type Format of string (time, date or datetime)
333
format_str String to parse
334
format_length Length of string
335
date_time_format Format to fill in
338
Fills in date_time_format->positions for all date time parts.
340
positions marks the position for a datetime element in the format string.
341
The position array elements are in the following order:
342
YYYY-DD-MM HH-MM-DD.FFFFFF AM
345
If positions[0]= 5, it means that year will be the forth element to
346
read from the parsed date string.
353
bool parse_date_time_format(timestamp_type format_type,
354
const char *format, uint format_length,
355
DATE_TIME_FORMAT *date_time_format)
357
uint offset= 0, separators= 0;
358
const char *ptr= format, *format_str;
359
const char *end= ptr+format_length;
360
uchar *dt_pos= date_time_format->positions;
361
/* need_p is set if we are using AM/PM format */
362
bool need_p= 0, allow_separator= 0;
363
ulong part_map= 0, separator_map= 0;
364
const char *parts[16];
366
date_time_format->time_separator= 0;
367
date_time_format->flag= 0; // For future
370
Fill position with 'dummy' arguments to found out if a format tag is
371
used twice (This limit's the format to 255 characters, but this is ok)
373
dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]=
374
dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= 255;
376
for (; ptr != end; ptr++)
378
if (*ptr == '%' && ptr+1 != end)
397
need_p= 1; // Need AM/PM
412
if (dt_pos[5] != offset-1 || ptr[-2] != '.')
413
return 1; // Wrong usage of %f
416
if (offset == 0) // Can't be first
421
return 1; // Unknown controll char
423
if (dt_pos[position] != 255) // Don't allow same tag twice
425
parts[position]= ptr-1;
428
If switching from time to date, ensure that all time parts
431
if (part_map && position <= 2 && !(part_map & (1 | 2 | 4)))
433
part_map|= (ulong) 1 << position;
434
dt_pos[position]= offset++;
440
Don't allow any characters in format as this could easily confuse
443
if (!allow_separator)
444
return 1; // No separator here
445
allow_separator= 0; // Don't allow two separators
447
/* Store in separator_map which parts are punct characters */
448
if (my_ispunct(&my_charset_latin1, *ptr))
449
separator_map|= (ulong) 1 << (offset-1);
450
else if (!my_isspace(&my_charset_latin1, *ptr))
455
/* If no %f, specify it after seconds. Move %p up, if necessary */
456
if ((part_map & 32) && !(part_map & 64))
458
dt_pos[6]= dt_pos[5] +1;
459
parts[6]= parts[5]; // For later test in (need_p)
460
if (dt_pos[6] == dt_pos[7]) // Move %p one step up if used
465
Check that we have not used a non legal format specifier and that all
466
format specifiers have been used
468
The last test is to ensure that %p is used if and only if
471
if ((format_type == MYSQL_TIMESTAMP_DATETIME &&
472
!test_all_bits(part_map, (1 | 2 | 4 | 8 | 16 | 32))) ||
473
(format_type == MYSQL_TIMESTAMP_DATE && part_map != (1 | 2 | 4)) ||
474
(format_type == MYSQL_TIMESTAMP_TIME &&
475
!test_all_bits(part_map, 8 | 16 | 32)) ||
476
!allow_separator || // %option should be last
477
(need_p && dt_pos[6] +1 != dt_pos[7]) ||
478
(need_p ^ (dt_pos[7] != 255)))
481
if (dt_pos[6] != 255) // If fractional seconds
483
/* remove fractional seconds from later tests */
484
uint pos= dt_pos[6] -1;
485
/* Remove separator before %f from sep map */
486
separator_map= ((separator_map & ((ulong) (1 << pos)-1)) |
487
((separator_map & ~((ulong) (1 << pos)-1)) >> 1));
490
separators--; // There is always a separator
491
need_p= 1; // force use of separators
496
Remove possible separator before %p from sep_map
497
(This can either be at position 3, 4, 6 or 7) h.m.d.%f %p
499
if (dt_pos[7] != 255)
501
if (need_p && parts[7] != parts[6]+2)
505
Calculate if %p is in first or last part of the datetime field
507
At this point we have either %H-%i-%s %p 'year parts' or
508
'year parts' &H-%i-%s %p" as %f was removed above
510
offset= dt_pos[6] <= 3 ? 3 : 6;
511
/* Remove separator before %p from sep map */
512
separator_map= ((separator_map & ((ulong) (1 << offset)-1)) |
513
((separator_map & ~((ulong) (1 << offset)-1)) >> 1));
516
switch (format_type) {
517
case MYSQL_TIMESTAMP_DATE:
518
format_str= known_date_time_formats[INTERNAL_FORMAT].date_format;
520
case MYSQL_TIMESTAMP_TIME:
522
format_str=known_date_time_formats[INTERNAL_FORMAT].time_format;
525
If there is no separators, allow the internal format as we can read
526
this. If separators are used, they must be between each part
528
if (format_length == 6 && !need_p &&
529
!my_strnncoll(&my_charset_bin,
530
(const uchar *) format, 6,
531
(const uchar *) format_str, 6))
533
if (separator_map == (1 | 2))
535
if (format_type == MYSQL_TIMESTAMP_TIME)
537
if (*(format+2) != *(format+5))
539
/* Store the character used for time formats */
540
date_time_format->time_separator= *(format+2);
545
case MYSQL_TIMESTAMP_DATETIME:
547
If there is no separators, allow the internal format as we can read
548
this. If separators are used, they must be between each part.
549
Between DATE and TIME we also allow space as separator
551
if ((format_length == 12 && !need_p &&
552
!my_strnncoll(&my_charset_bin,
553
(const uchar *) format, 12,
554
(const uchar*) known_date_time_formats[INTERNAL_FORMAT].datetime_format,
556
(separators == 5 && separator_map == (1 | 2 | 8 | 16)))
568
Create a DATE_TIME_FORMAT object from a format string specification
571
date_time_format_make()
572
format_type Format to parse (time, date or datetime)
573
format_str String to parse
574
format_length Length of string
577
The returned object should be freed with my_free()
585
*date_time_format_make(timestamp_type format_type,
586
const char *format_str, uint format_length)
588
DATE_TIME_FORMAT tmp;
590
if (format_length && format_length < 255 &&
591
!parse_date_time_format(format_type, format_str,
592
format_length, &tmp))
594
tmp.format.str= (char*) format_str;
595
tmp.format.length= format_length;
596
return date_time_format_copy((THD *)0, &tmp);
603
Create a copy of a DATE_TIME_FORMAT object
606
date_and_time_format_copy()
607
thd Set if variable should be allocated in thread mem
608
format format to copy
611
The returned object should be freed with my_free()
618
DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format)
620
DATE_TIME_FORMAT *new_format;
621
ulong length= sizeof(*format) + format->format.length + 1;
624
new_format= (DATE_TIME_FORMAT *) thd->alloc(length);
626
new_format= (DATE_TIME_FORMAT *) my_malloc(length, MYF(MY_WME));
629
/* Put format string after current pos */
630
new_format->format.str= (char*) (new_format+1);
631
memcpy((char*) new_format->positions, (char*) format->positions,
632
sizeof(format->positions));
633
new_format->time_separator= format->time_separator;
634
/* We make the string null terminated for easy printf in SHOW VARIABLES */
635
memcpy((char*) new_format->format.str, format->format.str,
636
format->format.length);
637
new_format->format.str[format->format.length]= 0;
638
new_format->format.length= format->format.length;
644
KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]=
646
{"USA", "%m.%d.%Y", "%Y-%m-%d %H.%i.%s", "%h:%i:%s %p" },
647
{"JIS", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
648
{"ISO", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
649
{"EUR", "%d.%m.%Y", "%Y-%m-%d %H.%i.%s", "%H.%i.%s" },
650
{"INTERNAL", "%Y%m%d", "%Y%m%d%H%i%s", "%H%i%s" },
656
Return format string according format name.
657
If name is unknown, result is NULL
660
const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
664
case MYSQL_TIMESTAMP_DATE:
665
return format->date_format;
666
case MYSQL_TIMESTAMP_DATETIME:
667
return format->datetime_format;
668
case MYSQL_TIMESTAMP_TIME:
669
return format->time_format;
671
DBUG_ASSERT(0); // Impossible
676
/****************************************************************************
677
Functions to create default time/date/datetime strings
680
For the moment the DATE_TIME_FORMAT argument is ignored becasue
681
MySQL doesn't support comparing of date/time/datetime strings that
682
are not in arbutary order as dates are compared as strings in some
684
This functions don't check that given MYSQL_TIME structure members are
685
in valid range. If they are not, return value won't reflect any
686
valid date either. Additionally, make_time doesn't take into
687
account time->day member: it's assumed that days have been converted
689
****************************************************************************/
691
void make_time(const DATE_TIME_FORMAT *format __attribute__((unused)),
692
const MYSQL_TIME *l_time, String *str)
694
uint length= (uint) my_time_to_str(l_time, (char*) str->ptr());
696
str->set_charset(&my_charset_bin);
700
void make_date(const DATE_TIME_FORMAT *format __attribute__((unused)),
701
const MYSQL_TIME *l_time, String *str)
703
uint length= (uint) my_date_to_str(l_time, (char*) str->ptr());
705
str->set_charset(&my_charset_bin);
709
void make_datetime(const DATE_TIME_FORMAT *format __attribute__((unused)),
710
const MYSQL_TIME *l_time, String *str)
712
uint length= (uint) my_datetime_to_str(l_time, (char*) str->ptr());
714
str->set_charset(&my_charset_bin);
718
void make_truncated_value_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
720
uint str_length, timestamp_type time_type,
721
const char *field_name)
723
char warn_buff[MYSQL_ERRMSG_SIZE];
724
const char *type_str;
725
CHARSET_INFO *cs= &my_charset_latin1;
727
String str(buff,(uint32) sizeof(buff), system_charset_info);
728
str.copy(str_val, str_length, system_charset_info);
729
str[str_length]= 0; // Ensure we have end 0 for snprintf
732
case MYSQL_TIMESTAMP_DATE:
735
case MYSQL_TIMESTAMP_TIME:
738
case MYSQL_TIMESTAMP_DATETIME: // FALLTHROUGH
740
type_str= "datetime";
744
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
745
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
746
type_str, str.c_ptr(), field_name,
747
(ulong) thd->row_count);
750
if (time_type > MYSQL_TIMESTAMP_ERROR)
751
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
752
ER(ER_TRUNCATED_WRONG_VALUE),
753
type_str, str.c_ptr());
755
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
756
ER(ER_WRONG_VALUE), type_str, str.c_ptr());
758
push_warning(thd, level,
759
ER_TRUNCATED_WRONG_VALUE, warn_buff);
762
/* Daynumber from year 0 to 9999-12-31 */
763
#define MAX_DAY_NUMBER 3652424L
765
bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type, INTERVAL interval)
771
sign= (interval.neg ? -1 : 1);
774
case INTERVAL_SECOND:
775
case INTERVAL_SECOND_MICROSECOND:
776
case INTERVAL_MICROSECOND:
777
case INTERVAL_MINUTE:
779
case INTERVAL_MINUTE_MICROSECOND:
780
case INTERVAL_MINUTE_SECOND:
781
case INTERVAL_HOUR_MICROSECOND:
782
case INTERVAL_HOUR_SECOND:
783
case INTERVAL_HOUR_MINUTE:
784
case INTERVAL_DAY_MICROSECOND:
785
case INTERVAL_DAY_SECOND:
786
case INTERVAL_DAY_MINUTE:
787
case INTERVAL_DAY_HOUR:
789
longlong sec, days, daynr, microseconds, extra_sec;
790
ltime->time_type= MYSQL_TIMESTAMP_DATETIME; // Return full date
791
microseconds= ltime->second_part + sign*interval.second_part;
792
extra_sec= microseconds/1000000L;
793
microseconds= microseconds%1000000L;
795
sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
797
sign* (longlong) (interval.day*3600*24L +
798
interval.hour*LL(3600)+interval.minute*LL(60)+
799
interval.second))+ extra_sec;
800
if (microseconds < 0)
802
microseconds+= LL(1000000);
805
days= sec/(3600*LL(24));
806
sec-= days*3600*LL(24);
812
ltime->second_part= (uint) microseconds;
813
ltime->second= (uint) (sec % 60);
814
ltime->minute= (uint) (sec/60 % 60);
815
ltime->hour= (uint) (sec/3600);
816
daynr= calc_daynr(ltime->year,ltime->month,1) + days;
817
/* Day number from year 0 to 9999-12-31 */
818
if ((ulonglong) daynr > MAX_DAY_NUMBER)
820
get_date_from_daynr((long) daynr, <ime->year, <ime->month,
826
period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
827
sign * (long) interval.day);
828
/* Daynumber from year 0 to 9999-12-31 */
829
if ((ulong) period > MAX_DAY_NUMBER)
831
get_date_from_daynr((long) period,<ime->year,<ime->month,<ime->day);
834
ltime->year+= sign * (long) interval.year;
835
if ((ulong) ltime->year >= 10000L)
837
if (ltime->month == 2 && ltime->day == 29 &&
838
calc_days_in_year(ltime->year) != 366)
839
ltime->day=28; // Was leap-year
841
case INTERVAL_YEAR_MONTH:
842
case INTERVAL_QUARTER:
844
period= (ltime->year*12 + sign * (long) interval.year*12 +
845
ltime->month-1 + sign * (long) interval.month);
846
if ((ulong) period >= 120000L)
848
ltime->year= (uint) (period / 12);
849
ltime->month= (uint) (period % 12L)+1;
850
/* Adjust day if the new month doesn't have enough days */
851
if (ltime->day > days_in_month[ltime->month-1])
853
ltime->day = days_in_month[ltime->month-1];
854
if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
855
ltime->day++; // Leap-year
865
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
866
ER_DATETIME_FUNCTION_OVERFLOW,
867
ER(ER_DATETIME_FUNCTION_OVERFLOW),
875
Calculate difference between two datetime values as seconds + microseconds.
879
l_time1 - TIME/DATE/DATETIME value
880
l_time2 - TIME/DATE/DATETIME value
881
l_sign - 1 absolute values are substracted,
882
-1 absolute values are added.
883
seconds_out - Out parameter where difference between
884
l_time1 and l_time2 in seconds is stored.
885
microseconds_out- Out parameter where microsecond part of difference
886
between l_time1 and l_time2 is stored.
889
This function calculates difference between l_time1 and l_time2 absolute
890
values. So one should set l_sign and correct result if he want to take
891
signs into account (i.e. for MYSQL_TIME values).
894
Returns sign of difference.
895
1 means negative result
896
0 means positive result
901
calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign, longlong *seconds_out,
902
long *microseconds_out)
906
longlong microseconds;
909
We suppose that if first argument is MYSQL_TIMESTAMP_TIME
910
the second argument should be TIMESTAMP_TIME also.
911
We should check it before calc_time_diff call.
913
if (l_time1->time_type == MYSQL_TIMESTAMP_TIME) // Time value
914
days= (long)l_time1->day - l_sign * (long)l_time2->day;
917
days= calc_daynr((uint) l_time1->year,
918
(uint) l_time1->month,
919
(uint) l_time1->day);
920
if (l_time2->time_type == MYSQL_TIMESTAMP_TIME)
921
days-= l_sign * (long)l_time2->day;
923
days-= l_sign*calc_daynr((uint) l_time2->year,
924
(uint) l_time2->month,
925
(uint) l_time2->day);
928
microseconds= ((longlong)days*LL(86400) +
929
(longlong)(l_time1->hour*3600L +
930
l_time1->minute*60L +
932
l_sign*(longlong)(l_time2->hour*3600L +
933
l_time2->minute*60L +
934
l_time2->second)) * LL(1000000) +
935
(longlong)l_time1->second_part -
936
l_sign*(longlong)l_time2->second_part;
939
if (microseconds < 0)
941
microseconds= -microseconds;
944
*seconds_out= microseconds/1000000L;
945
*microseconds_out= (long) (microseconds%1000000L);
951
Compares 2 MYSQL_TIME structures
965
TIME.second_part is not considered during comparison
969
my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b)
971
my_ulonglong a_t= TIME_to_ulonglong_datetime(a);
972
my_ulonglong b_t= TIME_to_ulonglong_datetime(b);