~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/my_time.cc

enable remaining subselect tests, merge with latest from the trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
 along with this program; if not, write to the Free Software
14
14
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
 
#include <my_time.h>
 
16
#include "mysys_priv.h"
 
17
 
 
18
#include "my_time.h"
 
19
 
17
20
#include <mystrings/m_string.h>
18
21
#include <mystrings/m_ctype.h>
 
22
#include <drizzled/util/test.h>
 
23
 
 
24
#include <stdio.h>
19
25
/* Windows version of localtime_r() is declared in my_ptrhead.h */
20
26
 
21
27
uint64_t log_10_int[20]=
30
36
 
31
37
/* Position for YYYY-DD-MM HH-MM-DD.FFFFFF AM in default format */
32
38
 
33
 
static uchar internal_format_positions[]=
34
 
{0, 1, 2, 3, 4, 5, 6, (uchar) 255};
 
39
static unsigned char internal_format_positions[]=
 
40
{0, 1, 2, 3, 4, 5, 6, (unsigned char) 255};
35
41
 
36
42
static char time_separator=':';
37
43
 
38
44
static uint32_t const days_at_timestart=719528; /* daynr at 1970.01.01 */
39
 
uchar days_in_month[]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
 
45
unsigned char days_in_month[]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
40
46
 
41
47
/*
42
 
  Offset of system time zone from UTC in seconds used to speed up 
 
48
  Offset of system time zone from UTC in seconds used to speed up
43
49
  work of my_system_gmt_sec() function.
44
50
*/
45
51
static long my_time_zone=0;
47
53
 
48
54
/* Calc days in one year. works with 0 <= year <= 99 */
49
55
 
50
 
uint calc_days_in_year(uint year)
 
56
uint32_t calc_days_in_year(uint32_t year)
51
57
{
52
58
  return ((year & 3) == 0 && (year%100 || (year%400 == 0 && year)) ?
53
59
          366 : 365);
156
162
#define MAX_DATE_PARTS 8
157
163
 
158
164
enum enum_drizzle_timestamp_type
159
 
str_to_datetime(const char *str, uint length, DRIZZLE_TIME *l_time,
160
 
                uint flags, int *was_cut)
 
165
str_to_datetime(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
 
166
                uint32_t flags, int *was_cut)
161
167
{
162
 
  uint field_length, year_length=4, digits, i, number_of_fields;
163
 
  uint date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS];
164
 
  uint add_hours= 0, start_loop;
 
168
  uint32_t field_length, year_length=4, digits, i, number_of_fields;
 
169
  uint32_t date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS];
 
170
  uint32_t add_hours= 0, start_loop;
165
171
  uint32_t not_zero_date, allow_space;
166
172
  bool is_internal_format;
167
173
  const char *pos, *last_field_pos=NULL;
168
174
  const char *end=str+length;
169
 
  const uchar *format_position;
 
175
  const unsigned char *format_position;
170
176
  bool found_delimitier= 0, found_space= 0;
171
 
  uint frac_pos, frac_len;
 
177
  uint32_t frac_pos, frac_len;
172
178
 
173
179
  *was_cut= 0;
174
180
 
175
181
  /* Skip space at start */
176
 
  for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++)
 
182
  for (; str != end && my_isspace(&my_charset_utf8_general_ci, *str) ; str++)
177
183
    ;
178
 
  if (str == end || ! my_isdigit(&my_charset_latin1, *str))
 
184
  if (str == end || ! my_isdigit(&my_charset_utf8_general_ci, *str))
179
185
  {
180
186
    *was_cut= 1;
181
187
    return(DRIZZLE_TIMESTAMP_NONE);
191
197
    (YYYY-MM-DD,  YYYYMMDD, YYYYYMMDDHHMMSS)
192
198
  */
193
199
  for (pos=str;
194
 
       pos != end && (my_isdigit(&my_charset_latin1,*pos) || *pos == 'T');
 
200
       pos != end && (my_isdigit(&my_charset_utf8_general_ci,*pos) || *pos == 'T');
195
201
       pos++)
196
202
    ;
197
203
 
216
222
        We do this by checking if there is two numbers separated by
217
223
        space in the input.
218
224
      */
219
 
      while (pos < end && !my_isspace(&my_charset_latin1, *pos))
 
225
      while (pos < end && !my_isspace(&my_charset_utf8_general_ci, *pos))
220
226
        pos++;
221
 
      while (pos < end && !my_isdigit(&my_charset_latin1, *pos))
 
227
      while (pos < end && !my_isdigit(&my_charset_utf8_general_ci, *pos))
222
228
        pos++;
223
229
      if (pos == end)
224
230
      {
244
250
    2003-03-03 20:00:20 AM
245
251
    20:00:20.000000 AM 03-03-2000
246
252
  */
247
 
  i= max((uint) format_position[0], (uint) format_position[1]);
 
253
  i= cmax((uint) format_position[0], (uint) format_position[1]);
248
254
  set_if_bigger(i, (uint) format_position[2]);
249
255
  allow_space= ((1 << i) | (1 << format_position[6]));
250
256
  allow_space&= (1 | 2 | 4 | 8);
252
258
  not_zero_date= 0;
253
259
  for (i = start_loop;
254
260
       i < MAX_DATE_PARTS-1 && str != end &&
255
 
         my_isdigit(&my_charset_latin1,*str);
 
261
         my_isdigit(&my_charset_utf8_general_ci,*str);
256
262
       i++)
257
263
  {
258
264
    const char *start= str;
259
 
    uint32_t tmp_value= (uint) (uchar) (*str++ - '0');
260
 
    while (str != end && my_isdigit(&my_charset_latin1,str[0]) &&
 
265
    uint32_t tmp_value= (uint) (unsigned char) (*str++ - '0');
 
266
    while (str != end && my_isdigit(&my_charset_utf8_general_ci,str[0]) &&
261
267
           (!is_internal_format || --field_length))
262
268
    {
263
 
      tmp_value=tmp_value*10 + (uint32_t) (uchar) (*str - '0');
 
269
      tmp_value=tmp_value*10 + (uint32_t) (unsigned char) (*str - '0');
264
270
      str++;
265
271
    }
266
272
    date_len[i]= (uint) (str - start);
296
302
      continue;
297
303
    }
298
304
    while (str != end &&
299
 
           (my_ispunct(&my_charset_latin1,*str) ||
300
 
            my_isspace(&my_charset_latin1,*str)))
 
305
           (my_ispunct(&my_charset_utf8_general_ci,*str) ||
 
306
            my_isspace(&my_charset_utf8_general_ci,*str)))
301
307
    {
302
 
      if (my_isspace(&my_charset_latin1,*str))
 
308
      if (my_isspace(&my_charset_utf8_general_ci,*str))
303
309
      {
304
310
        if (!(allow_space & (1 << i)))
305
311
        {
325
331
            continue;                           /* Not AM/PM */
326
332
          str+= 2;                              /* Skip AM/PM */
327
333
          /* Skip space after AM/PM */
328
 
          while (str != end && my_isspace(&my_charset_latin1,*str))
 
334
          while (str != end && my_isspace(&my_charset_utf8_general_ci,*str))
329
335
            str++;
330
336
        }
331
337
      }
369
375
      date[frac_pos]*= (uint) log_10_int[6 - frac_len];
370
376
    l_time->second_part= date[frac_pos];
371
377
 
372
 
    if (format_position[7] != (uchar) 255)
 
378
    if (format_position[7] != (unsigned char) 255)
373
379
    {
374
380
      if (l_time->hour > 12)
375
381
      {
406
412
    {
407
413
      for (; str != end ; str++)
408
414
      {
409
 
        if (!my_isspace(&my_charset_latin1, *str))
 
415
        if (!my_isspace(&my_charset_utf8_general_ci, *str))
410
416
        {
411
417
          not_zero_date= 1;                     /* Give warning */
412
418
          break;
425
431
 
426
432
  for (; str != end ; str++)
427
433
  {
428
 
    if (!my_isspace(&my_charset_latin1,*str))
 
434
    if (!my_isspace(&my_charset_utf8_general_ci,*str))
429
435
    {
430
436
      *was_cut= 1;
431
437
      break;
467
473
     1  error
468
474
*/
469
475
 
470
 
bool str_to_time(const char *str, uint length, DRIZZLE_TIME *l_time,
 
476
bool str_to_time(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
471
477
                    int *warning)
472
478
{
473
479
  uint32_t date[5];
474
480
  uint64_t value;
475
481
  const char *end=str+length, *end_of_days;
476
482
  bool found_days,found_hours;
477
 
  uint state;
 
483
  uint32_t state;
478
484
 
479
485
  l_time->neg=0;
480
486
  *warning= 0;
481
 
  for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++)
 
487
  for (; str != end && my_isspace(&my_charset_utf8_general_ci,*str) ; str++)
482
488
    length--;
483
489
  if (str != end && *str == '-')
484
490
  {
505
511
  }
506
512
 
507
513
  /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
508
 
  for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
 
514
  for (value=0; str != end && my_isdigit(&my_charset_utf8_general_ci,*str) ; str++)
509
515
    value=value*10L + (long) (*str - '0');
510
516
 
511
517
  /* Skip all space after 'days' */
512
518
  end_of_days= str;
513
 
  for (; str != end && my_isspace(&my_charset_latin1, str[0]) ; str++)
 
519
  for (; str != end && my_isspace(&my_charset_utf8_general_ci, str[0]) ; str++)
514
520
    ;
515
521
 
516
522
  found_days=found_hours=0;
517
523
  if ((uint) (end-str) > 1 && str != end_of_days &&
518
 
      my_isdigit(&my_charset_latin1, *str))
 
524
      my_isdigit(&my_charset_utf8_general_ci, *str))
519
525
  {                                             /* Found days part */
520
526
    date[0]= (uint32_t) value;
521
527
    state= 1;                                   /* Assume next is hours */
522
528
    found_days= 1;
523
529
  }
524
530
  else if ((end-str) > 1 &&  *str == time_separator &&
525
 
           my_isdigit(&my_charset_latin1, str[1]))
 
531
           my_isdigit(&my_charset_utf8_general_ci, str[1]))
526
532
  {
527
533
    date[0]= 0;                                 /* Assume we found hours */
528
534
    date[1]= (uint32_t) value;
544
550
  /* Read hours, minutes and seconds */
545
551
  for (;;)
546
552
  {
547
 
    for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
 
553
    for (value=0; str != end && my_isdigit(&my_charset_utf8_general_ci,*str) ; str++)
548
554
      value=value*10L + (long) (*str - '0');
549
555
    date[state++]= (uint32_t) value;
550
556
    if (state == 4 || (end-str) < 2 || *str != time_separator ||
551
 
        !my_isdigit(&my_charset_latin1,str[1]))
 
557
        !my_isdigit(&my_charset_utf8_general_ci,str[1]))
552
558
      break;
553
559
    str++;                                      /* Skip time_separator (':') */
554
560
  }
558
564
    /* Fix the date to assume that seconds was given */
559
565
    if (!found_hours && !found_days)
560
566
    {
561
 
      bmove_upp((uchar*) (date+4), (uchar*) (date+state),
 
567
      bmove_upp((unsigned char*) (date+4), (unsigned char*) (date+state),
562
568
                sizeof(long)*(state-1));
563
569
      memset(date, 0, sizeof(long)*(4-state));
564
570
    }
568
574
 
569
575
fractional:
570
576
  /* Get fractional second part */
571
 
  if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1]))
 
577
  if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_utf8_general_ci,str[1]))
572
578
  {
573
579
    int field_length= 5;
574
 
    str++; value=(uint) (uchar) (*str - '0');
575
 
    while (++str != end && my_isdigit(&my_charset_latin1, *str))
 
580
    str++; value=(uint) (unsigned char) (*str - '0');
 
581
    while (++str != end && my_isdigit(&my_charset_utf8_general_ci, *str))
576
582
    {
577
583
      if (field_length-- > 0)
578
 
        value= value*10 + (uint) (uchar) (*str - '0');
 
584
        value= value*10 + (uint) (unsigned char) (*str - '0');
579
585
    }
580
586
    if (field_length > 0)
581
587
      value*= (long) log_10_int[field_length];
585
591
  }
586
592
  else
587
593
    date[4]=0;
588
 
    
 
594
 
589
595
  /* Check for exponent part: E<gigit> | E<sign><digit> */
590
596
  /* (may occur as result of %g formatting of time value) */
591
597
  if ((end - str) > 1 &&
592
598
      (*str == 'e' || *str == 'E') &&
593
 
      (my_isdigit(&my_charset_latin1, str[1]) ||
 
599
      (my_isdigit(&my_charset_utf8_general_ci, str[1]) ||
594
600
       ((str[1] == '-' || str[1] == '+') &&
595
601
        (end - str) > 2 &&
596
 
        my_isdigit(&my_charset_latin1, str[2]))))
 
602
        my_isdigit(&my_charset_utf8_general_ci, str[2]))))
597
603
    return 1;
598
604
 
599
605
  if (internal_format_positions[7] != 255)
600
606
  {
601
607
    /* Read a possible AM/PM */
602
 
    while (str != end && my_isspace(&my_charset_latin1, *str))
 
608
    while (str != end && my_isspace(&my_charset_utf8_general_ci, *str))
603
609
      str++;
604
610
    if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
605
611
    {
618
624
      date[2] > UINT_MAX || date[3] > UINT_MAX ||
619
625
      date[4] > UINT_MAX)
620
626
    return 1;
621
 
  
 
627
 
622
628
  l_time->year=         0;                      /* For protocol::store_time */
623
629
  l_time->month=        0;
624
630
  l_time->day=          date[0];
631
637
  /* Check if the value is valid and fits into DRIZZLE_TIME range */
632
638
  if (check_time_range(l_time, warning))
633
639
    return 1;
634
 
  
 
640
 
635
641
  /* Check if there is garbage at end of the DRIZZLE_TIME specification */
636
642
  if (str != end)
637
643
  {
638
644
    do
639
645
    {
640
 
      if (!my_isspace(&my_charset_latin1,*str))
 
646
      if (!my_isspace(&my_charset_utf8_general_ci,*str))
641
647
      {
642
648
        *warning|= DRIZZLE_TIME_WARN_TRUNCATED;
643
649
        break;
666
672
    1        time value is invalid
667
673
*/
668
674
 
669
 
int check_time_range(DRIZZLE_TIME *my_time, int *warning) 
 
675
int check_time_range(DRIZZLE_TIME *my_time, int *warning)
670
676
{
671
677
  int64_t hour;
672
678
 
727
733
    Year between 1970-2069
728
734
*/
729
735
 
730
 
uint year_2000_handling(uint year)
 
736
uint32_t year_2000_handling(uint32_t year)
731
737
{
732
738
  if ((year=year+1900) < 1900+YY_PART_YEAR)
733
739
    year+=100;
750
756
    Days since 0000-00-00
751
757
*/
752
758
 
753
 
long calc_daynr(uint year,uint month,uint day)
 
759
long calc_daynr(uint32_t year,uint32_t month,uint32_t day)
754
760
{
755
761
  long delsum;
756
762
  int temp;
769
775
 
770
776
/*
771
777
  Convert time in DRIZZLE_TIME representation in system time zone to its
772
 
  my_time_t form (number of seconds in UTC since begginning of Unix Epoch).
 
778
  time_t form (number of seconds in UTC since begginning of Unix Epoch).
773
779
 
774
780
  SYNOPSIS
775
781
    my_system_gmt_sec()
779
785
      in_dst_time_gap - set to true if time falls into spring time-gap
780
786
 
781
787
  NOTES
782
 
    The idea is to cache the time zone offset from UTC (including daylight 
783
 
    saving time) for the next call to make things faster. But currently we 
784
 
    just calculate this offset during startup (by calling init_time() 
 
788
    The idea is to cache the time zone offset from UTC (including daylight
 
789
    saving time) for the next call to make things faster. But currently we
 
790
    just calculate this offset during startup (by calling init_time()
785
791
    function) and use it all the time.
786
792
    Time value provided should be legal time value (e.g. '2003-01-01 25:00:00'
787
793
    is not allowed).
789
795
  RETURN VALUE
790
796
    Time in UTC seconds since Unix Epoch representation.
791
797
*/
792
 
my_time_t
 
798
time_t
793
799
my_system_gmt_sec(const DRIZZLE_TIME *t_src, long *my_timezone,
794
800
                  bool *in_dst_time_gap)
795
801
{
796
 
  uint loop;
 
802
  uint32_t loop;
797
803
  time_t tmp= 0;
798
804
  int shift= 0;
799
805
  DRIZZLE_TIME tmp_time;
975
981
  if ((tmp < TIMESTAMP_MIN_VALUE) || (tmp > TIMESTAMP_MAX_VALUE))
976
982
    tmp= 0;
977
983
 
978
 
  return (my_time_t) tmp;
 
984
  return (time_t) tmp;
979
985
} /* my_system_gmt_sec */
980
986
 
981
987
 
1003
1009
 
1004
1010
int my_time_to_str(const DRIZZLE_TIME *l_time, char *to)
1005
1011
{
1006
 
  uint extra_hours= 0;
 
1012
  uint32_t extra_hours= 0;
1007
1013
  return sprintf(to, "%s%02u:%02u:%02u",
1008
1014
                         (l_time->neg ? "-" : ""),
1009
1015
                         extra_hours+ l_time->hour,
1089
1095
*/
1090
1096
 
1091
1097
int64_t number_to_datetime(int64_t nr, DRIZZLE_TIME *time_res,
1092
 
                            uint flags, int *was_cut)
 
1098
                            uint32_t flags, int *was_cut)
1093
1099
{
1094
1100
  long part1,part2;
1095
1101