~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/time.cc

  • Committer: Jay Pipes
  • Date: 2009-02-28 17:49:22 UTC
  • mto: (910.2.6 mordred-noatomics)
  • mto: This revision was merged to the branch mainline in revision 908.
  • Revision ID: jpipes@serialcoder-20090228174922-jczgt4d0662fqmnf
Merging in old r902 temporal changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include <drizzled/util/test.h>
26
26
#include <drizzled/tztime.h>
27
27
#include <drizzled/session.h>
28
 
#include <drizzled/function/time/get_format.h>
29
28
 
30
29
/* Some functions to calculate dates */
31
30
 
328
327
  to->second_part= microseconds;
329
328
}
330
329
 
331
 
 
332
 
/*
333
 
  Parse a format string specification
334
 
 
335
 
  SYNOPSIS
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
341
 
 
342
 
  NOTES
343
 
    Fills in date_time_format->positions for all date time parts.
344
 
 
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
348
 
    0    1  2  3  4  5  6      7
349
 
 
350
 
    If positions[0]= 5, it means that year will be the forth element to
351
 
    read from the parsed date string.
352
 
 
353
 
  RETURN
354
 
    0   ok
355
 
    1   error
356
 
*/
357
 
 
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)
361
 
{
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];
370
 
 
371
 
  date_time_format->time_separator= 0;
372
 
  date_time_format->flag= 0;                    // For future
373
 
 
374
 
  /*
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)
377
 
  */
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;
380
 
 
381
 
  for (; ptr != end; ptr++)
382
 
  {
383
 
    if (*ptr == '%' && ptr+1 != end)
384
 
    {
385
 
      uint32_t position;
386
 
      switch (*++ptr) {
387
 
      case 'y':                                 // Year
388
 
      case 'Y':
389
 
        position= 0;
390
 
        break;
391
 
      case 'c':                                 // Month
392
 
      case 'm':
393
 
        position= 1;
394
 
        break;
395
 
      case 'd':
396
 
      case 'e':
397
 
        position= 2;
398
 
        break;
399
 
      case 'h':
400
 
      case 'I':
401
 
      case 'l':
402
 
        need_p= 1;                              // Need AM/PM
403
 
        /* Fall through */
404
 
      case 'k':
405
 
      case 'H':
406
 
        position= 3;
407
 
        break;
408
 
      case 'i':
409
 
        position= 4;
410
 
        break;
411
 
      case 's':
412
 
      case 'S':
413
 
        position= 5;
414
 
        break;
415
 
      case 'f':
416
 
        position= 6;
417
 
        if (dt_pos[5] != offset-1 || ptr[-2] != '.')
418
 
          return 1;                             // Wrong usage of %f
419
 
        break;
420
 
      case 'p':                                 // AM/PM
421
 
        if (offset == 0)                        // Can't be first
422
 
          return 0;
423
 
        position= 7;
424
 
        break;
425
 
      default:
426
 
        return 1;                               // Unknown controll char
427
 
      }
428
 
      if (dt_pos[position] != 255)              // Don't allow same tag twice
429
 
        return 1;
430
 
      parts[position]= ptr-1;
431
 
 
432
 
      /*
433
 
        If switching from time to date, ensure that all time parts
434
 
        are used
435
 
      */
436
 
      if (part_map && position <= 2 && !(part_map & (1 | 2 | 4)))
437
 
        offset=5;
438
 
      part_map|= UINT32_C(1) << position;
439
 
      dt_pos[position]= offset++;
440
 
      allow_separator= 1;
441
 
    }
442
 
    else
443
 
    {
444
 
      /*
445
 
        Don't allow any characters in format as this could easily confuse
446
 
        the date reader
447
 
      */
448
 
      if (!allow_separator)
449
 
        return 1;                               // No separator here
450
 
      allow_separator= 0;                       // Don't allow two separators
451
 
      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))
456
 
        return 1;
457
 
    }
458
 
  }
459
 
 
460
 
  /* If no %f, specify it after seconds.  Move %p up, if necessary */
461
 
  if ((part_map & 32) && !(part_map & 64))
462
 
  {
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
466
 
      dt_pos[7]++;
467
 
  }
468
 
 
469
 
  /*
470
 
    Check that we have not used a non legal format specifier and that all
471
 
    format specifiers have been used
472
 
 
473
 
    The last test is to ensure that %p is used if and only if
474
 
    it's needed.
475
 
  */
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)))
484
 
    return 1;
485
 
 
486
 
  if (dt_pos[6] != 255)                         // If fractional seconds
487
 
  {
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));
493
 
    if (part_map & 64)
494
 
    {
495
 
      separators--;                             // There is always a separator
496
 
      need_p= 1;                                // force use of separators
497
 
    }
498
 
  }
499
 
 
500
 
  /*
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
503
 
  */
504
 
  if (dt_pos[7] != 255)
505
 
  {
506
 
    if (need_p && parts[7] != parts[6]+2)
507
 
      separators--;
508
 
  }
509
 
  /*
510
 
    Calculate if %p is in first or last part of the datetime field
511
 
 
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
514
 
  */
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));
519
 
 
520
 
  format_str= 0;
521
 
  switch (format_type) {
522
 
  case DRIZZLE_TIMESTAMP_DATE:
523
 
    format_str= known_date_time_formats[INTERNAL_FORMAT].date_format;
524
 
    /* fall through */
525
 
  case DRIZZLE_TIMESTAMP_TIME:
526
 
    if (!format_str)
527
 
      format_str=known_date_time_formats[INTERNAL_FORMAT].time_format;
528
 
 
529
 
    /*
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
532
 
    */
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))
537
 
      return 0;
538
 
    if (separator_map == (1 | 2))
539
 
    {
540
 
      if (format_type == DRIZZLE_TIMESTAMP_TIME)
541
 
      {
542
 
        if (*(format+2) != *(format+5))
543
 
          break;                                // Error
544
 
        /* Store the character used for time formats */
545
 
        date_time_format->time_separator= *(format+2);
546
 
      }
547
 
      return 0;
548
 
    }
549
 
    break;
550
 
  case DRIZZLE_TIMESTAMP_DATETIME:
551
 
    /*
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
555
 
    */
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,
560
 
                       12)) ||
561
 
        (separators == 5 && separator_map == (1 | 2 | 8 | 16)))
562
 
      return 0;
563
 
    break;
564
 
  default:
565
 
    assert(1);
566
 
    break;
567
 
  }
568
 
  return 1;                                     // Error
569
 
}
570
 
 
571
 
 
572
 
/*
573
 
  Create a DATE_TIME_FORMAT object from a format string specification
574
 
 
575
 
  SYNOPSIS
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
580
 
 
581
 
  NOTES
582
 
    The returned object should be freed with free()
583
 
 
584
 
  RETURN
585
 
    NULL ponter:        Error
586
 
    new object
587
 
*/
588
 
 
589
 
DATE_TIME_FORMAT
590
 
*date_time_format_make(enum enum_drizzle_timestamp_type format_type,
591
 
                       const char *format_str, uint32_t format_length)
592
 
{
593
 
  DATE_TIME_FORMAT tmp;
594
 
 
595
 
  if (format_length && format_length < 255 &&
596
 
      !parse_date_time_format(format_type, format_str,
597
 
                              format_length, &tmp))
598
 
  {
599
 
    tmp.format.str=    (char*) format_str;
600
 
    tmp.format.length= format_length;
601
 
    return date_time_format_copy((Session *)0, &tmp);
602
 
  }
603
 
  return 0;
604
 
}
605
 
 
606
 
 
607
 
/*
608
 
  Create a copy of a DATE_TIME_FORMAT object
609
 
 
610
 
  SYNOPSIS
611
 
    date_and_time_format_copy()
612
 
    session                     Set if variable should be allocated in thread mem
613
 
    format              format to copy
614
 
 
615
 
  NOTES
616
 
    The returned object should be freed with free()
617
 
 
618
 
  RETURN
619
 
    NULL ponter:        Error
620
 
    new object
621
 
*/
622
 
 
623
 
DATE_TIME_FORMAT *date_time_format_copy(Session *session, DATE_TIME_FORMAT *format)
624
 
{
625
 
  DATE_TIME_FORMAT *new_format;
626
 
  uint32_t length= sizeof(*format) + format->format.length + 1;
627
 
 
628
 
  if (session)
629
 
    new_format= (DATE_TIME_FORMAT *) session->alloc(length);
630
 
  else
631
 
    new_format=  (DATE_TIME_FORMAT *) malloc(length);
632
 
  if (new_format)
633
 
  {
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;
644
 
  }
645
 
  return new_format;
646
 
}
647
 
 
648
 
 
649
 
KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]=
650
 
{
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" },
656
 
  { 0, 0, 0, 0 }
657
 
};
658
 
 
659
 
 
660
 
/*
661
 
   Return format string according format name.
662
 
   If name is unknown, result is NULL
663
 
*/
664
 
 
665
 
const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
666
 
                                     enum enum_drizzle_timestamp_type type)
667
 
{
668
 
  switch (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;
675
 
  default:
676
 
    assert(0);                          // Impossible
677
 
    return 0;
678
 
  }
679
 
}
680
 
 
681
 
/****************************************************************************
682
 
  Functions to create default time/date/datetime strings
683
 
 
684
 
  NOTE:
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
688
 
    context)
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
693
 
    to hours already.
694
 
****************************************************************************/
695
 
 
696
 
void make_time(const DATE_TIME_FORMAT *,
697
 
               const DRIZZLE_TIME *l_time, String *str)
698
 
{
699
 
  uint32_t length= (uint32_t) my_time_to_str(l_time, (char*) str->ptr());
700
 
  str->length(length);
701
 
  str->set_charset(&my_charset_bin);
702
 
}
703
 
 
704
 
 
705
 
void make_date(const DATE_TIME_FORMAT *,
706
 
               const DRIZZLE_TIME *l_time, String *str)
707
 
{
708
 
  uint32_t length= (uint32_t) my_date_to_str(l_time, (char*) str->ptr());
709
 
  str->length(length);
710
 
  str->set_charset(&my_charset_bin);
711
 
}
712
 
 
713
 
 
714
 
void make_datetime(const DATE_TIME_FORMAT *,
715
 
                   const DRIZZLE_TIME *l_time, String *str)
716
 
{
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)
 
331
{
 
332
  uint32_t length= (uint32_t) my_time_to_str(l_time, (char*) str->c_ptr());
 
333
  str->length(length);
 
334
  str->set_charset(&my_charset_bin);
 
335
}
 
336
 
 
337
 
 
338
void make_date(const DRIZZLE_TIME *l_time, String *str)
 
339
{
 
340
  uint32_t length= (uint32_t) my_date_to_str(l_time, (char*) str->c_ptr());
 
341
  str->length(length);
 
342
  str->set_charset(&my_charset_bin);
 
343
}
 
344
 
 
345
 
 
346
void make_datetime(const DRIZZLE_TIME *l_time, String *str)
 
347
{
 
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);
720
351
}