328
327
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());
330
void make_time(const DRIZZLE_TIME *l_time, String *str)
332
uint32_t length= (uint32_t) my_time_to_str(l_time, (char*) str->c_ptr());
334
str->set_charset(&my_charset_bin);
338
void make_date(const DRIZZLE_TIME *l_time, String *str)
340
uint32_t length= (uint32_t) my_date_to_str(l_time, (char*) str->c_ptr());
342
str->set_charset(&my_charset_bin);
346
void make_datetime(const DRIZZLE_TIME *l_time, String *str)
348
uint32_t length= (uint32_t) my_datetime_to_str(l_time, (char*) str->c_ptr());
718
349
str->length(length);
719
350
str->set_charset(&my_charset_bin);