21
21
/* Functions to handle date and time */
24
#include "drizzled/error.h"
25
#include "drizzled/util/test.h"
26
#include "drizzled/tztime.h"
27
#include "drizzled/session.h"
28
#include "drizzled/time_functions.h"
23
#include <drizzled/server_includes.h>
24
#include <drizzled/error.h>
25
#include <drizzled/util/test.h>
26
#include <drizzled/tztime.h>
27
#include <drizzled/session.h>
28
#include <drizzled/function/time/get_format.h>
33
30
/* Some functions to calculate dates */
35
Name description of interval names used in statements.
37
'interval_type_to_name' is ordered and sorted on interval size and
39
Order of elements in 'interval_type_to_name' should correspond to
40
the order of elements in 'interval_type' enum
42
See also interval_type, interval_names
45
LEX_STRING interval_type_to_name[INTERVAL_LAST] = {
46
{ C_STRING_WITH_LEN("YEAR")},
47
{ C_STRING_WITH_LEN("QUARTER")},
48
{ C_STRING_WITH_LEN("MONTH")},
49
{ C_STRING_WITH_LEN("WEEK")},
50
{ C_STRING_WITH_LEN("DAY")},
51
{ C_STRING_WITH_LEN("HOUR")},
52
{ C_STRING_WITH_LEN("MINUTE")},
53
{ C_STRING_WITH_LEN("SECOND")},
54
{ C_STRING_WITH_LEN("MICROSECOND")},
55
{ C_STRING_WITH_LEN("YEAR_MONTH")},
56
{ C_STRING_WITH_LEN("DAY_HOUR")},
57
{ C_STRING_WITH_LEN("DAY_MINUTE")},
58
{ C_STRING_WITH_LEN("DAY_SECOND")},
59
{ C_STRING_WITH_LEN("HOUR_MINUTE")},
60
{ C_STRING_WITH_LEN("HOUR_SECOND")},
61
{ C_STRING_WITH_LEN("MINUTE_SECOND")},
62
{ C_STRING_WITH_LEN("DAY_MICROSECOND")},
63
{ C_STRING_WITH_LEN("HOUR_MICROSECOND")},
64
{ C_STRING_WITH_LEN("MINUTE_MICROSECOND")},
65
{ C_STRING_WITH_LEN("SECOND_MICROSECOND")}
68
/* Calc weekday from daynr */
69
/* Returns 0 for monday, 1 for tuesday .... */
36
71
int calc_weekday(long daynr,bool sunday_first_day_of_week)
38
73
return ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
42
uint32_t calc_week(type::Time *l_time, uint32_t week_behaviour, uint32_t *year)
77
The bits in week_format has the following meaning:
78
WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week
79
If set Monday is first day of week
80
WEEK_YEAR (1) If not set Week is in range 0-53
82
Week 0 is returned for the the last week of the previous year (for
83
a date at start of january) In this case one can get 53 for the
84
first week of next year. This flag ensures that the week is
85
relevant for the given year. Note that this flag is only
86
releveant if WEEK_JANUARY is not set.
88
If set Week is in range 1-53.
90
In this case one may get week 53 for a date in January (when
91
the week is that last week of previous year) and week 1 for a
94
WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according
96
If set The week that contains the first
97
'first-day-of-week' is week 1.
99
ISO 8601:1988 means that if the week containing January 1 has
100
four or more days in the new year, then it is week 1;
101
Otherwise it is the last week of the previous year, and the
105
uint32_t calc_week(DRIZZLE_TIME *l_time, uint32_t week_behaviour, uint32_t *year)
45
108
uint32_t daynr= calc_daynr(l_time->year,l_time->month,l_time->day);
127
type::timestamp_t str_to_datetime_with_warn(Session *session,
133
type::cut_t was_cut= type::VALID;
134
type::timestamp_t ts_type;
136
ts_type= l_time->store(str, length,
137
(flags | (session->variables.sql_mode &
138
(MODE_INVALID_DATES |
139
MODE_NO_ZERO_DATE))),
141
if (was_cut || ts_type <= type::DRIZZLE_TIMESTAMP_ERROR)
142
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
189
/* Functions to handle periods */
191
uint32_t convert_period_to_month(uint32_t period)
196
if ((a=period/100) < YY_PART_YEAR)
205
uint32_t convert_month_to_period(uint32_t month)
210
if ((year=month/12) < 100)
212
year+=(year < YY_PART_YEAR) ? 2000 : 1900;
214
return year*100+month%12+1;
219
Convert a timestamp string to a DRIZZLE_TIME value and produce a warning
220
if string was truncated during conversion.
223
See description of str_to_datetime() for more information.
226
enum enum_drizzle_timestamp_type
227
str_to_datetime_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
231
Session *session= current_session;
232
enum enum_drizzle_timestamp_type ts_type;
234
ts_type= str_to_datetime(str, length, l_time,
235
(flags | (session->variables.sql_mode &
236
(MODE_INVALID_DATES |
237
MODE_NO_ZERO_DATE))),
239
if (was_cut || ts_type <= DRIZZLE_TIMESTAMP_ERROR)
240
make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
143
241
str, length, ts_type, NULL);
247
Convert a datetime from broken-down DRIZZLE_TIME representation to corresponding
252
session - current thread
253
t - datetime in broken-down representation,
254
in_dst_time_gap - pointer to bool which is set to true if t represents
255
value which doesn't exists (falls into the spring
256
time-gap) or to false otherwise.
259
Number seconds in UTC since start of Unix Epoch corresponding to t.
260
0 - t contains datetime value which is out of TIMESTAMP range.
263
time_t TIME_to_timestamp(Session *session, const DRIZZLE_TIME *t,
264
bool *in_dst_time_gap)
270
timestamp= session->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap);
276
/* If we are here we have range error. */
282
Convert a time string to a DRIZZLE_TIME struct and produce a warning
283
if string was cut during conversion.
286
See str_to_time() for more info.
150
str_to_time_with_warn(Session *session, const char *str, uint32_t length, type::Time *l_time)
289
str_to_time_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time)
153
bool ret_val= l_time->store(str, length, warning, type::DRIZZLE_TIMESTAMP_TIME);
292
bool ret_val= str_to_time(str, length, l_time, &warning);
154
293
if (ret_val || warning)
155
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
156
str, length, type::DRIZZLE_TIMESTAMP_TIME, NULL);
294
make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
295
str, length, DRIZZLE_TIMESTAMP_TIME, NULL);
161
void make_truncated_value_warning(Session *session,
162
DRIZZLE_ERROR::enum_warning_level level,
301
Convert a system time structure to TIME
304
void localtime_to_TIME(DRIZZLE_TIME *to, struct tm *from)
308
to->year= (int) ((from->tm_year+1900) % 10000);
309
to->month= (int) from->tm_mon+1;
310
to->day= (int) from->tm_mday;
311
to->hour= (int) from->tm_hour;
312
to->minute= (int) from->tm_min;
313
to->second= (int) from->tm_sec;
316
void calc_time_from_sec(DRIZZLE_TIME *to, long seconds, long microseconds)
319
// to->neg is not cleared, it may already be set to a useful value
320
to->time_type= DRIZZLE_TIMESTAMP_TIME;
324
to->hour= seconds/3600L;
325
t_seconds= seconds%3600L;
326
to->minute= t_seconds/60L;
327
to->second= t_seconds%60L;
328
to->second_part= microseconds;
333
Parse a format string specification
336
parse_date_time_format()
337
format_type Format of string (time, date or datetime)
338
format_str String to parse
339
format_length Length of string
340
date_time_format Format to fill in
343
Fills in date_time_format->positions for all date time parts.
345
positions marks the position for a datetime element in the format string.
346
The position array elements are in the following order:
347
YYYY-DD-MM HH-MM-DD.FFFFFF AM
350
If positions[0]= 5, it means that year will be the forth element to
351
read from the parsed date string.
358
bool parse_date_time_format(enum enum_drizzle_timestamp_type format_type,
359
const char *format, uint32_t format_length,
360
DATE_TIME_FORMAT *date_time_format)
362
uint32_t offset= 0, separators= 0;
363
const char *ptr= format, *format_str;
364
const char *end= ptr+format_length;
365
unsigned char *dt_pos= date_time_format->positions;
366
/* need_p is set if we are using AM/PM format */
367
bool need_p= 0, allow_separator= 0;
368
uint32_t part_map= 0, separator_map= 0;
369
const char *parts[16];
371
date_time_format->time_separator= 0;
372
date_time_format->flag= 0; // For future
375
Fill position with 'dummy' arguments to found out if a format tag is
376
used twice (This limit's the format to 255 characters, but this is ok)
378
dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]=
379
dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= 255;
381
for (; ptr != end; ptr++)
383
if (*ptr == '%' && ptr+1 != end)
402
need_p= 1; // Need AM/PM
417
if (dt_pos[5] != offset-1 || ptr[-2] != '.')
418
return 1; // Wrong usage of %f
421
if (offset == 0) // Can't be first
426
return 1; // Unknown controll char
428
if (dt_pos[position] != 255) // Don't allow same tag twice
430
parts[position]= ptr-1;
433
If switching from time to date, ensure that all time parts
436
if (part_map && position <= 2 && !(part_map & (1 | 2 | 4)))
438
part_map|= UINT32_C(1) << position;
439
dt_pos[position]= offset++;
445
Don't allow any characters in format as this could easily confuse
448
if (!allow_separator)
449
return 1; // No separator here
450
allow_separator= 0; // Don't allow two separators
452
/* Store in separator_map which parts are punct characters */
453
if (my_ispunct(&my_charset_utf8_general_ci, *ptr))
454
separator_map|= 1 << (offset-1);
455
else if (!my_isspace(&my_charset_utf8_general_ci, *ptr))
460
/* If no %f, specify it after seconds. Move %p up, if necessary */
461
if ((part_map & 32) && !(part_map & 64))
463
dt_pos[6]= dt_pos[5] +1;
464
parts[6]= parts[5]; // For later test in (need_p)
465
if (dt_pos[6] == dt_pos[7]) // Move %p one step up if used
470
Check that we have not used a non legal format specifier and that all
471
format specifiers have been used
473
The last test is to ensure that %p is used if and only if
476
if ((format_type == DRIZZLE_TIMESTAMP_DATETIME &&
477
!test_all_bits(part_map, (uint32_t) (1 | 2 | 4 | 8 | 16 | 32))) ||
478
(format_type == DRIZZLE_TIMESTAMP_DATE && part_map != (1 | 2 | 4)) ||
479
(format_type == DRIZZLE_TIMESTAMP_TIME &&
480
!test_all_bits(part_map, (uint32_t) (8 | 16 | 32))) ||
481
!allow_separator || // %option should be last
482
(need_p && dt_pos[6] +1 != dt_pos[7]) ||
483
(need_p ^ (dt_pos[7] != 255)))
486
if (dt_pos[6] != 255) // If fractional seconds
488
/* remove fractional seconds from later tests */
489
uint32_t pos= dt_pos[6] -1;
490
/* Remove separator before %f from sep map */
491
separator_map= ((separator_map & ((1 << pos)-1)) |
492
((separator_map & ~((1 << pos)-1)) >> 1));
495
separators--; // There is always a separator
496
need_p= 1; // force use of separators
501
Remove possible separator before %p from sep_map
502
(This can either be at position 3, 4, 6 or 7) h.m.d.%f %p
504
if (dt_pos[7] != 255)
506
if (need_p && parts[7] != parts[6]+2)
510
Calculate if %p is in first or last part of the datetime field
512
At this point we have either %H-%i-%s %p 'year parts' or
513
'year parts' &H-%i-%s %p" as %f was removed above
515
offset= dt_pos[6] <= 3 ? 3 : 6;
516
/* Remove separator before %p from sep map */
517
separator_map= ((separator_map & ((1 << offset)-1)) |
518
((separator_map & ~((1 << offset)-1)) >> 1));
521
switch (format_type) {
522
case DRIZZLE_TIMESTAMP_DATE:
523
format_str= known_date_time_formats[INTERNAL_FORMAT].date_format;
525
case DRIZZLE_TIMESTAMP_TIME:
527
format_str=known_date_time_formats[INTERNAL_FORMAT].time_format;
530
If there is no separators, allow the internal format as we can read
531
this. If separators are used, they must be between each part
533
if (format_length == 6 && !need_p &&
534
!my_strnncoll(&my_charset_bin,
535
(const unsigned char *) format, 6,
536
(const unsigned char *) format_str, 6))
538
if (separator_map == (1 | 2))
540
if (format_type == DRIZZLE_TIMESTAMP_TIME)
542
if (*(format+2) != *(format+5))
544
/* Store the character used for time formats */
545
date_time_format->time_separator= *(format+2);
550
case DRIZZLE_TIMESTAMP_DATETIME:
552
If there is no separators, allow the internal format as we can read
553
this. If separators are used, they must be between each part.
554
Between DATE and TIME we also allow space as separator
556
if ((format_length == 12 && !need_p &&
557
!my_strnncoll(&my_charset_bin,
558
(const unsigned char *) format, 12,
559
(const unsigned char*) known_date_time_formats[INTERNAL_FORMAT].datetime_format,
561
(separators == 5 && separator_map == (1 | 2 | 8 | 16)))
573
Create a DATE_TIME_FORMAT object from a format string specification
576
date_time_format_make()
577
format_type Format to parse (time, date or datetime)
578
format_str String to parse
579
format_length Length of string
582
The returned object should be freed with free()
590
*date_time_format_make(enum enum_drizzle_timestamp_type format_type,
591
const char *format_str, uint32_t format_length)
593
DATE_TIME_FORMAT tmp;
595
if (format_length && format_length < 255 &&
596
!parse_date_time_format(format_type, format_str,
597
format_length, &tmp))
599
tmp.format.str= (char*) format_str;
600
tmp.format.length= format_length;
601
return date_time_format_copy((Session *)0, &tmp);
608
Create a copy of a DATE_TIME_FORMAT object
611
date_and_time_format_copy()
612
session Set if variable should be allocated in thread mem
613
format format to copy
616
The returned object should be freed with free()
623
DATE_TIME_FORMAT *date_time_format_copy(Session *session, DATE_TIME_FORMAT *format)
625
DATE_TIME_FORMAT *new_format;
626
uint32_t length= sizeof(*format) + format->format.length + 1;
629
new_format= (DATE_TIME_FORMAT *) session->alloc(length);
631
new_format= (DATE_TIME_FORMAT *) malloc(length);
634
/* Put format string after current pos */
635
new_format->format.str= (char*) (new_format+1);
636
memcpy(new_format->positions, format->positions,
637
sizeof(format->positions));
638
new_format->time_separator= format->time_separator;
639
/* We make the string null terminated for easy printf in SHOW VARIABLES */
640
memcpy(new_format->format.str, format->format.str,
641
format->format.length);
642
new_format->format.str[format->format.length]= 0;
643
new_format->format.length= format->format.length;
649
KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]=
651
{"USA", "%m.%d.%Y", "%Y-%m-%d %H.%i.%s", "%h:%i:%s %p" },
652
{"JIS", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
653
{"ISO", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
654
{"EUR", "%d.%m.%Y", "%Y-%m-%d %H.%i.%s", "%H.%i.%s" },
655
{"INTERNAL", "%Y%m%d", "%Y%m%d%H%i%s", "%H%i%s" },
661
Return format string according format name.
662
If name is unknown, result is NULL
665
const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
666
enum enum_drizzle_timestamp_type type)
669
case DRIZZLE_TIMESTAMP_DATE:
670
return format->date_format;
671
case DRIZZLE_TIMESTAMP_DATETIME:
672
return format->datetime_format;
673
case DRIZZLE_TIMESTAMP_TIME:
674
return format->time_format;
676
assert(0); // Impossible
681
/****************************************************************************
682
Functions to create default time/date/datetime strings
685
For the moment the DATE_TIME_FORMAT argument is ignored becasue
686
MySQL doesn't support comparing of date/time/datetime strings that
687
are not in arbutary order as dates are compared as strings in some
689
This functions don't check that given DRIZZLE_TIME structure members are
690
in valid range. If they are not, return value won't reflect any
691
valid date either. Additionally, make_time doesn't take into
692
account time->day member: it's assumed that days have been converted
694
****************************************************************************/
696
void make_time(const DATE_TIME_FORMAT *,
697
const DRIZZLE_TIME *l_time, String *str)
699
uint32_t length= (uint32_t) my_time_to_str(l_time, (char*) str->ptr());
701
str->set_charset(&my_charset_bin);
705
void make_date(const DATE_TIME_FORMAT *,
706
const DRIZZLE_TIME *l_time, String *str)
708
uint32_t length= (uint32_t) my_date_to_str(l_time, (char*) str->ptr());
710
str->set_charset(&my_charset_bin);
714
void make_datetime(const DATE_TIME_FORMAT *,
715
const DRIZZLE_TIME *l_time, String *str)
717
uint32_t length= (uint32_t) my_datetime_to_str(l_time, (char*) str->ptr());
719
str->set_charset(&my_charset_bin);
723
void make_truncated_value_warning(Session *session, DRIZZLE_ERROR::enum_warning_level level,
163
724
const char *str_val,
165
type::timestamp_t time_type,
726
enum enum_drizzle_timestamp_type time_type,
166
727
const char *field_name)
168
729
char warn_buff[DRIZZLE_ERRMSG_SIZE];
174
735
str[str_length]= 0; // Ensure we have end 0 for snprintf
176
737
switch (time_type) {
177
case type::DRIZZLE_TIMESTAMP_DATE:
181
case type::DRIZZLE_TIMESTAMP_TIME:
185
case type::DRIZZLE_TIMESTAMP_DATETIME: // FALLTHROUGH
187
type_str= "datetime";
738
case DRIZZLE_TIMESTAMP_DATE:
741
case DRIZZLE_TIMESTAMP_TIME:
744
case DRIZZLE_TIMESTAMP_DATETIME: // FALLTHROUGH
746
type_str= "datetime";
193
750
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
194
751
ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
195
752
type_str, str.c_ptr(), field_name,
196
753
(uint32_t) session->row_count);
200
if (time_type > type::DRIZZLE_TIMESTAMP_ERROR)
756
if (time_type > DRIZZLE_TIMESTAMP_ERROR)
202
757
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
203
758
ER(ER_TRUNCATED_WRONG_VALUE),
204
759
type_str, str.c_ptr());
208
761
cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
209
762
ER(ER_WRONG_VALUE), type_str, str.c_ptr());
212
764
push_warning(session, level,
213
765
ER_TRUNCATED_WRONG_VALUE, warn_buff);
768
bool date_add_interval(DRIZZLE_TIME *ltime, interval_type int_type, INTERVAL interval)
774
sign= (interval.neg ? -1 : 1);
777
case INTERVAL_SECOND:
778
case INTERVAL_SECOND_MICROSECOND:
779
case INTERVAL_MICROSECOND:
780
case INTERVAL_MINUTE:
782
case INTERVAL_MINUTE_MICROSECOND:
783
case INTERVAL_MINUTE_SECOND:
784
case INTERVAL_HOUR_MICROSECOND:
785
case INTERVAL_HOUR_SECOND:
786
case INTERVAL_HOUR_MINUTE:
787
case INTERVAL_DAY_MICROSECOND:
788
case INTERVAL_DAY_SECOND:
789
case INTERVAL_DAY_MINUTE:
790
case INTERVAL_DAY_HOUR:
792
int64_t sec, days, daynr, microseconds, extra_sec;
793
ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME; // Return full date
794
microseconds= ltime->second_part + sign*interval.second_part;
795
extra_sec= microseconds/1000000L;
796
microseconds= microseconds%1000000L;
798
sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
800
sign* (int64_t) (interval.day*3600*24L +
801
interval.hour*3600L+interval.minute*60L+
802
interval.second))+ extra_sec;
803
if (microseconds < 0)
805
microseconds+= 1000000L;
808
days= sec/(3600*24L);
815
ltime->second_part= (uint32_t) microseconds;
816
ltime->second= (uint32_t) (sec % 60);
817
ltime->minute= (uint32_t) (sec/60 % 60);
818
ltime->hour= (uint32_t) (sec/3600);
819
daynr= calc_daynr(ltime->year,ltime->month,1) + days;
820
/* Day number from year 0 to 9999-12-31 */
821
if ((uint64_t) daynr > MAX_DAY_NUMBER)
823
get_date_from_daynr((long) daynr, <ime->year, <ime->month,
829
period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
830
sign * (long) interval.day);
831
/* Daynumber from year 0 to 9999-12-31 */
832
if (period > MAX_DAY_NUMBER)
834
get_date_from_daynr((long) period,<ime->year,<ime->month,<ime->day);
837
ltime->year+= sign * (long) interval.year;
838
if (ltime->year >= 10000L)
840
if (ltime->month == 2 && ltime->day == 29 &&
841
calc_days_in_year(ltime->year) != 366)
842
ltime->day=28; // Was leap-year
844
case INTERVAL_YEAR_MONTH:
845
case INTERVAL_QUARTER:
847
period= (ltime->year*12 + sign * (long) interval.year*12 +
848
ltime->month-1 + sign * (long) interval.month);
849
if (period >= 120000L)
851
ltime->year= (uint32_t) (period / 12);
852
ltime->month= (uint32_t) (period % 12L)+1;
853
/* Adjust day if the new month doesn't have enough days */
854
if (ltime->day > days_in_month[ltime->month-1])
856
ltime->day = days_in_month[ltime->month-1];
857
if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
858
ltime->day++; // Leap-year
868
push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
869
ER_DATETIME_FUNCTION_OVERFLOW,
870
ER(ER_DATETIME_FUNCTION_OVERFLOW),
878
Calculate difference between two datetime values as seconds + microseconds.
882
l_time1 - TIME/DATE/DATETIME value
883
l_time2 - TIME/DATE/DATETIME value
884
l_sign - 1 absolute values are substracted,
885
-1 absolute values are added.
886
seconds_out - Out parameter where difference between
887
l_time1 and l_time2 in seconds is stored.
888
microseconds_out- Out parameter where microsecond part of difference
889
between l_time1 and l_time2 is stored.
892
This function calculates difference between l_time1 and l_time2 absolute
893
values. So one should set l_sign and correct result if he want to take
894
signs into account (i.e. for DRIZZLE_TIME values).
897
Returns sign of difference.
898
1 means negative result
899
0 means positive result
218
calc_time_diff(type::Time *l_time1, type::Time *l_time2, int l_sign, int64_t *seconds_out,
904
calc_time_diff(DRIZZLE_TIME *l_time1, DRIZZLE_TIME *l_time2, int l_sign, int64_t *seconds_out,
219
905
long *microseconds_out)