~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/drizzle_time.cc

  • Committer: Brian Aker
  • Date: 2010-12-25 00:28:49 UTC
  • mto: This revision was merged to the branch mainline in revision 2031.
  • Revision ID: brian@tangent.org-20101225002849-g73mg6ihulajis0o
First pass in refactoring of the name of my_decimal.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 
16
16
#include "config.h"
17
17
 
18
 
#include "drizzled/type/time.h"
19
 
 
20
 
#include <drizzled/util/gmtime.h>
 
18
#include "drizzled/drizzle_time.h"
21
19
 
22
20
#include "drizzled/internal/m_string.h"
23
21
#include "drizzled/charset_info.h"
24
22
#include <drizzled/util/test.h>
25
23
#include "drizzled/definitions.h"
26
 
#include <drizzled/sql_string.h>
27
24
 
28
25
#include <cstdio>
29
26
#include <algorithm>
33
30
namespace drizzled
34
31
{
35
32
 
36
 
static int check_time_range(type::Time *my_time, int *warning);
 
33
static int check_time_range(DRIZZLE_TIME *my_time, int *warning);
37
34
 
38
35
/* Windows version of localtime_r() is declared in my_ptrhead.h */
39
36
 
72
69
          366 : 365);
73
70
}
74
71
 
75
 
 
76
 
namespace type {
77
72
/**
78
73
  @brief Check datetime value for validity according to flags.
79
74
 
80
75
  @param[in]  ltime          Date to check.
81
76
  @param[in]  not_zero_date  ltime is not the zero date
82
77
  @param[in]  flags          flags to check
83
 
                             (see store() flags in drizzle_time.h)
 
78
                             (see str_to_datetime() flags in drizzle_time.h)
84
79
  @param[out] was_cut        set to 2 if value was invalid according to flags.
85
80
                             (Feb 29 in non-leap etc.)  This remains unchanged
86
81
                             if value is not invalid.
87
82
 
88
83
  @details Here we assume that year and month is ok!
89
84
    If month is 0 we allow any date. (This only happens if we allow zero
90
 
    date parts in store())
 
85
    date parts in str_to_datetime())
91
86
    Disallow dates with zero year and non-zero month and/or day.
92
87
 
93
88
  @return
95
90
    1  error
96
91
*/
97
92
 
98
 
bool Time::check(bool not_zero_date, uint32_t flags, type::cut_t &was_cut) const
 
93
bool check_date(const DRIZZLE_TIME *ltime, bool not_zero_date,
 
94
                   uint32_t flags, int *was_cut)
99
95
{
100
96
  if (not_zero_date)
101
97
  {
102
98
    if ((((flags & TIME_NO_ZERO_IN_DATE) || !(flags & TIME_FUZZY_DATE)) &&
103
 
         (month == 0 || day == 0)) ||
104
 
        (not (flags & TIME_INVALID_DATES) &&
105
 
         month && day > days_in_month[month-1] &&
106
 
         (month != 2 || calc_days_in_year(year) != 366 ||
107
 
          day != 29)))
 
99
         (ltime->month == 0 || ltime->day == 0)) ||
 
100
        (!(flags & TIME_INVALID_DATES) &&
 
101
         ltime->month && ltime->day > days_in_month[ltime->month-1] &&
 
102
         (ltime->month != 2 || calc_days_in_year(ltime->year) != 366 ||
 
103
          ltime->day != 29)))
108
104
    {
109
 
      was_cut= type::INVALID;
 
105
      *was_cut= 2;
110
106
      return true;
111
107
    }
112
108
  }
113
109
  else if (flags & TIME_NO_ZERO_DATE)
114
110
  {
115
111
    /*
116
 
      We don't set &was_cut here to signal that the problem was a zero date
 
112
      We don't set *was_cut here to signal that the problem was a zero date
117
113
      and not an invalid date
118
114
    */
119
115
    return true;
121
117
  return false;
122
118
}
123
119
 
 
120
 
124
121
/*
125
 
  Convert a timestamp string to a type::Time value.
 
122
  Convert a timestamp string to a DRIZZLE_TIME value.
126
123
 
127
124
  SYNOPSIS
128
 
    store()
 
125
    str_to_datetime()
129
126
    str                 String to parse
130
127
    length              Length of string
131
128
    l_time              Date is stored here
137
134
                        TIME_INVALID_DATES      Allow 2000-02-31
138
135
    was_cut             0       Value OK
139
136
                        1       If value was cut during conversion
140
 
                        2       check(date,flags) considers date invalid
 
137
                        2       check_date(date,flags) considers date invalid
141
138
 
142
139
  DESCRIPTION
143
140
    At least the following formats are recogniced (based on number of digits)
174
171
 
175
172
#define MAX_DATE_PARTS 8
176
173
 
177
 
type::timestamp_t Time::store(const char *str, uint32_t length, uint32_t flags, type::cut_t &was_cut)
 
174
enum enum_drizzle_timestamp_type
 
175
str_to_datetime(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
 
176
                uint32_t flags, int *was_cut)
178
177
{
179
178
  uint32_t field_length, year_length=4, digits, i, number_of_fields;
180
179
  uint32_t date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS];
187
186
  bool found_delimitier= 0, found_space= 0;
188
187
  uint32_t frac_pos, frac_len;
189
188
 
190
 
  was_cut= type::VALID;
 
189
  *was_cut= 0;
191
190
 
192
191
  /* Skip space at start */
193
192
  for (; str != end && my_isspace(&my_charset_utf8_general_ci, *str) ; str++)
194
193
    ;
195
 
 
196
194
  if (str == end || ! my_isdigit(&my_charset_utf8_general_ci, *str))
197
195
  {
198
 
    was_cut= type::CUT;
199
 
    return(type::DRIZZLE_TIMESTAMP_NONE);
 
196
    *was_cut= 1;
 
197
    return(DRIZZLE_TIMESTAMP_NONE);
200
198
  }
201
199
 
202
200
  is_internal_format= 0;
242
240
      {
243
241
        if (flags & TIME_DATETIME_ONLY)
244
242
        {
245
 
          was_cut= type::CUT;
246
 
          return(type::DRIZZLE_TIMESTAMP_NONE);   /* Can't be a full datetime */
 
243
          *was_cut= 1;
 
244
          return(DRIZZLE_TIMESTAMP_NONE);   /* Can't be a full datetime */
247
245
        }
248
246
        /* Date field.  Set hour, minutes and seconds to 0 */
249
247
        date[0]= date[1]= date[2]= date[3]= date[4]= 0;
284
282
    date_len[i]= (uint32_t) (str - start);
285
283
    if (tmp_value > 999999)                     /* Impossible date part */
286
284
    {
287
 
      was_cut= type::CUT;
288
 
      return(type::DRIZZLE_TIMESTAMP_NONE);
 
285
      *was_cut= 1;
 
286
      return(DRIZZLE_TIMESTAMP_NONE);
289
287
    }
290
288
    date[i]=tmp_value;
291
289
    not_zero_date|= tmp_value;
321
319
      {
322
320
        if (!(allow_space & (1 << i)))
323
321
        {
324
 
          was_cut= type::CUT;
325
 
          return(type::DRIZZLE_TIMESTAMP_NONE);
 
322
          *was_cut= 1;
 
323
          return(DRIZZLE_TIMESTAMP_NONE);
326
324
        }
327
325
        found_space= 1;
328
326
      }
352
350
  }
353
351
  if (found_delimitier && !found_space && (flags & TIME_DATETIME_ONLY))
354
352
  {
355
 
    was_cut= type::CUT;
356
 
    return(type::DRIZZLE_TIMESTAMP_NONE);          /* Can't be a datetime */
 
353
    *was_cut= 1;
 
354
    return(DRIZZLE_TIMESTAMP_NONE);          /* Can't be a datetime */
357
355
  }
358
356
 
359
357
  str= last_field_pos;
365
363
    date[i++]= 0;
366
364
  }
367
365
 
368
 
  do 
 
366
  if (!is_internal_format)
369
367
  {
370
 
    if (not is_internal_format)
371
 
    {
372
 
      year_length= date_len[(uint32_t) format_position[0]];
373
 
      if (!year_length)                           /* Year must be specified */
 
368
    year_length= date_len[(uint32_t) format_position[0]];
 
369
    if (!year_length)                           /* Year must be specified */
 
370
    {
 
371
      *was_cut= 1;
 
372
      return(DRIZZLE_TIMESTAMP_NONE);
 
373
    }
 
374
 
 
375
    l_time->year=               date[(uint32_t) format_position[0]];
 
376
    l_time->month=              date[(uint32_t) format_position[1]];
 
377
    l_time->day=                date[(uint32_t) format_position[2]];
 
378
    l_time->hour=               date[(uint32_t) format_position[3]];
 
379
    l_time->minute=             date[(uint32_t) format_position[4]];
 
380
    l_time->second=             date[(uint32_t) format_position[5]];
 
381
 
 
382
    frac_pos= (uint32_t) format_position[6];
 
383
    frac_len= date_len[frac_pos];
 
384
    if (frac_len < 6)
 
385
      date[frac_pos]*= (uint32_t) log_10_int[6 - frac_len];
 
386
    l_time->second_part= date[frac_pos];
 
387
 
 
388
    if (format_position[7] != (unsigned char) 255)
 
389
    {
 
390
      if (l_time->hour > 12)
374
391
      {
375
 
        was_cut= type::CUT;
376
 
        return(type::DRIZZLE_TIMESTAMP_NONE);
 
392
        *was_cut= 1;
 
393
        goto err;
377
394
      }
378
 
 
379
 
      this->year=               date[(uint32_t) format_position[0]];
380
 
      this->month=              date[(uint32_t) format_position[1]];
381
 
      this->day=                date[(uint32_t) format_position[2]];
382
 
      this->hour=               date[(uint32_t) format_position[3]];
383
 
      this->minute=             date[(uint32_t) format_position[4]];
384
 
      this->second=             date[(uint32_t) format_position[5]];
385
 
 
386
 
      frac_pos= (uint32_t) format_position[6];
387
 
      frac_len= date_len[frac_pos];
388
 
      if (frac_len < 6)
389
 
        date[frac_pos]*= (uint32_t) log_10_int[6 - frac_len];
390
 
      this->second_part= date[frac_pos];
391
 
 
392
 
      if (format_position[7] != (unsigned char) 255)
 
395
      l_time->hour= l_time->hour%12 + add_hours;
 
396
    }
 
397
  }
 
398
  else
 
399
  {
 
400
    l_time->year=       date[0];
 
401
    l_time->month=      date[1];
 
402
    l_time->day=        date[2];
 
403
    l_time->hour=       date[3];
 
404
    l_time->minute=     date[4];
 
405
    l_time->second=     date[5];
 
406
    if (date_len[6] < 6)
 
407
      date[6]*= (uint32_t) log_10_int[6 - date_len[6]];
 
408
    l_time->second_part=date[6];
 
409
  }
 
410
  l_time->neg= 0;
 
411
 
 
412
  if (year_length == 2 && not_zero_date)
 
413
    l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);
 
414
 
 
415
  if (number_of_fields < 3 ||
 
416
      l_time->year > 9999 || l_time->month > 12 ||
 
417
      l_time->day > 31 || l_time->hour > 23 ||
 
418
      l_time->minute > 59 || l_time->second > 59)
 
419
  {
 
420
    /* Only give warning for a zero date if there is some garbage after */
 
421
    if (!not_zero_date)                         /* If zero date */
 
422
    {
 
423
      for (; str != end ; str++)
393
424
      {
394
 
        if (this->hour > 12)
 
425
        if (!my_isspace(&my_charset_utf8_general_ci, *str))
395
426
        {
396
 
          was_cut= type::CUT;
 
427
          not_zero_date= 1;                     /* Give warning */
397
428
          break;
398
429
        }
399
 
        this->hour= this->hour%12 + add_hours;
400
 
      }
401
 
    }
402
 
    else
403
 
    {
404
 
      this->year=       date[0];
405
 
      this->month=      date[1];
406
 
      this->day=        date[2];
407
 
      this->hour=       date[3];
408
 
      this->minute=     date[4];
409
 
      this->second=     date[5];
410
 
      if (date_len[6] < 6)
411
 
        date[6]*= (uint32_t) log_10_int[6 - date_len[6]];
412
 
      this->second_part=date[6];
413
 
    }
414
 
    this->neg= 0;
415
 
 
416
 
    if (year_length == 2 && not_zero_date)
417
 
      this->year+= (this->year < YY_PART_YEAR ? 2000 : 1900);
418
 
 
419
 
    if (number_of_fields < 3 ||
420
 
        this->year > 9999 || this->month > 12 ||
421
 
        this->day > 31 || this->hour > 23 ||
422
 
        this->minute > 59 || this->second > 59)
423
 
    {
424
 
      /* Only give warning for a zero date if there is some garbage after */
425
 
      if (!not_zero_date)                         /* If zero date */
426
 
      {
427
 
        for (; str != end ; str++)
428
 
        {
429
 
          if (!my_isspace(&my_charset_utf8_general_ci, *str))
430
 
          {
431
 
            not_zero_date= 1;                     /* Give warning */
432
 
            break;
433
 
          }
434
 
        }
435
 
      }
436
 
      was_cut= test(not_zero_date) ? type::CUT : type::VALID;
437
 
      break;
438
 
    }
439
 
 
440
 
    if (check(not_zero_date != 0, flags, was_cut))
441
 
    {
442
 
      break;
443
 
    }
444
 
 
445
 
    this->time_type= (number_of_fields <= 3 ?
446
 
                      type::DRIZZLE_TIMESTAMP_DATE : type::DRIZZLE_TIMESTAMP_DATETIME);
447
 
 
448
 
    for (; str != end ; str++)
449
 
    {
450
 
      if (!my_isspace(&my_charset_utf8_general_ci,*str))
451
 
      {
452
 
        was_cut= type::CUT;
453
 
        break;
454
 
      }
455
 
    }
456
 
 
457
 
    return(time_type= (number_of_fields <= 3 ? type::DRIZZLE_TIMESTAMP_DATE : type::DRIZZLE_TIMESTAMP_DATETIME));
458
 
  } while (0);
459
 
 
460
 
  reset();
461
 
 
462
 
  return type::DRIZZLE_TIMESTAMP_ERROR;
463
 
}
464
 
 
465
 
type::timestamp_t Time::store(const char *str, uint32_t length, uint32_t flags)
466
 
{
467
 
  type::cut_t was_cut;
468
 
  return store(str, length, flags, was_cut);
469
 
}
 
430
      }
 
431
    }
 
432
    *was_cut= test(not_zero_date);
 
433
    goto err;
 
434
  }
 
435
 
 
436
  if (check_date(l_time, not_zero_date != 0, flags, was_cut))
 
437
    goto err;
 
438
 
 
439
  l_time->time_type= (number_of_fields <= 3 ?
 
440
                      DRIZZLE_TIMESTAMP_DATE : DRIZZLE_TIMESTAMP_DATETIME);
 
441
 
 
442
  for (; str != end ; str++)
 
443
  {
 
444
    if (!my_isspace(&my_charset_utf8_general_ci,*str))
 
445
    {
 
446
      *was_cut= 1;
 
447
      break;
 
448
    }
 
449
  }
 
450
 
 
451
  return(l_time->time_type=
 
452
              (number_of_fields <= 3 ? DRIZZLE_TIMESTAMP_DATE :
 
453
                                       DRIZZLE_TIMESTAMP_DATETIME));
 
454
 
 
455
err:
 
456
  memset(l_time, 0, sizeof(*l_time));
 
457
  return(DRIZZLE_TIMESTAMP_ERROR);
 
458
}
 
459
 
470
460
 
471
461
/*
472
 
 Convert a time string to a type::Time struct.
 
462
 Convert a time string to a DRIZZLE_TIME struct.
473
463
 
474
464
  SYNOPSIS
475
465
   str_to_time()
493
483
     1  error
494
484
*/
495
485
 
496
 
bool Time::store(const char *str, uint32_t length, int &warning, type::timestamp_t arg)
 
486
bool str_to_time(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
 
487
                    int *warning)
497
488
{
498
489
  uint32_t date[5];
499
490
  uint64_t value;
501
492
  bool found_days,found_hours;
502
493
  uint32_t state;
503
494
 
504
 
  assert(arg == DRIZZLE_TIMESTAMP_TIME);
505
 
 
506
 
  this->neg=0;
507
 
  warning= 0;
 
495
  l_time->neg=0;
 
496
  *warning= 0;
508
497
  for (; str != end && my_isspace(&my_charset_utf8_general_ci,*str) ; str++)
509
498
    length--;
510
499
  if (str != end && *str == '-')
511
500
  {
512
 
    this->neg=1;
 
501
    l_time->neg=1;
513
502
    str++;
514
503
    length--;
515
504
  }
516
505
  if (str == end)
517
 
    return true;
 
506
    return 1;
518
507
 
519
508
  /* Check first if this is a full TIMESTAMP */
520
509
  if (length >= 12)
521
510
  {                                             /* Probably full timestamp */
522
 
    type::cut_t was_cut;
523
 
    type::timestamp_t res= this->store(str, length, (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), was_cut);
524
 
    if ((int) res >= (int) type::DRIZZLE_TIMESTAMP_ERROR)
 
511
    int was_cut;
 
512
    enum enum_drizzle_timestamp_type
 
513
      res= str_to_datetime(str, length, l_time,
 
514
                           (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), &was_cut);
 
515
    if ((int) res >= (int) DRIZZLE_TIMESTAMP_ERROR)
525
516
    {
526
 
      if (was_cut != type::VALID)
527
 
        warning|= DRIZZLE_TIME_WARN_TRUNCATED;
528
 
 
529
 
      return res == type::DRIZZLE_TIMESTAMP_ERROR;
 
517
      if (was_cut)
 
518
        *warning|= DRIZZLE_TIME_WARN_TRUNCATED;
 
519
      return res == DRIZZLE_TIMESTAMP_ERROR;
530
520
    }
531
521
  }
532
522
 
604
594
        value= value*10 + (uint32_t) (unsigned char) (*str - '0');
605
595
    }
606
596
    if (field_length > 0)
607
 
    {
608
597
      value*= (long) log_10_int[field_length];
609
 
    }
610
598
    else if (field_length < 0)
611
 
    {
612
 
      warning|= DRIZZLE_TIME_WARN_TRUNCATED;
613
 
    }
614
 
 
 
599
      *warning|= DRIZZLE_TIME_WARN_TRUNCATED;
615
600
    date[4]= (uint32_t) value;
616
601
  }
617
602
  else
652
637
      date[4] > UINT_MAX)
653
638
    return 1;
654
639
 
655
 
  this->year=         0;                      /* For protocol::store_time */
656
 
  this->month=        0;
657
 
  this->day=          date[0];
658
 
  this->hour=         date[1];
659
 
  this->minute=       date[2];
660
 
  this->second=       date[3];
661
 
  this->second_part=  date[4];
662
 
  this->time_type= type::DRIZZLE_TIMESTAMP_TIME;
 
640
  l_time->year=         0;                      /* For protocol::store_time */
 
641
  l_time->month=        0;
 
642
  l_time->day=          date[0];
 
643
  l_time->hour=         date[1];
 
644
  l_time->minute=       date[2];
 
645
  l_time->second=       date[3];
 
646
  l_time->second_part=  date[4];
 
647
  l_time->time_type= DRIZZLE_TIMESTAMP_TIME;
663
648
 
664
 
  /* Check if the value is valid and fits into type::Time range */
665
 
  if (check_time_range(this, &warning))
 
649
  /* Check if the value is valid and fits into DRIZZLE_TIME range */
 
650
  if (check_time_range(l_time, warning))
666
651
  {
667
652
    return 1;
668
653
  }
669
654
 
670
 
  /* Check if there is garbage at end of the type::Time specification */
 
655
  /* Check if there is garbage at end of the DRIZZLE_TIME specification */
671
656
  if (str != end)
672
657
  {
673
658
    do
674
659
    {
675
660
      if (!my_isspace(&my_charset_utf8_general_ci,*str))
676
661
      {
677
 
        warning|= DRIZZLE_TIME_WARN_TRUNCATED;
 
662
        *warning|= DRIZZLE_TIME_WARN_TRUNCATED;
678
663
        break;
679
664
      }
680
665
    } while (++str != end);
682
667
  return 0;
683
668
}
684
669
 
685
 
} // namespace type
686
 
 
687
 
 
688
670
 
689
671
/*
690
 
  Check 'time' value to lie in the type::Time range
 
672
  Check 'time' value to lie in the DRIZZLE_TIME range
691
673
 
692
674
  SYNOPSIS:
693
675
    check_time_range()
694
 
    time     pointer to type::Time value
 
676
    time     pointer to DRIZZLE_TIME value
695
677
    warning  set DRIZZLE_TIME_WARN_OUT_OF_RANGE flag if the value is out of range
696
678
 
697
679
  DESCRIPTION
704
686
    1        time value is invalid
705
687
*/
706
688
 
707
 
static int check_time_range(type::Time *my_time, int *warning)
 
689
static int check_time_range(DRIZZLE_TIME *my_time, int *warning)
708
690
{
709
691
  int64_t hour;
710
692
 
737
719
{
738
720
  time_t seconds;
739
721
  struct tm *l_time,tm_tmp;
740
 
  type::Time my_time;
741
 
  type::Time::epoch_t epoch;
 
722
  DRIZZLE_TIME my_time;
742
723
  bool not_used;
743
724
 
744
725
  seconds= (time_t) time((time_t*) 0);
745
 
  localtime_r(&seconds, &tm_tmp);
 
726
  localtime_r(&seconds,&tm_tmp);
746
727
  l_time= &tm_tmp;
747
728
  my_time_zone=         3600;           /* Comp. for -3600 in my_gmt_sec */
748
729
  my_time.year=         (uint32_t) l_time->tm_year+1900;
751
732
  my_time.hour=         (uint32_t) l_time->tm_hour;
752
733
  my_time.minute=       (uint32_t) l_time->tm_min;
753
734
  my_time.second=       (uint32_t) l_time->tm_sec;
754
 
  my_time.time_type=    type::DRIZZLE_TIMESTAMP_NONE;
 
735
  my_time.time_type=    DRIZZLE_TIMESTAMP_NONE;
755
736
  my_time.second_part=  0;
756
737
  my_time.neg=          false;
757
 
  my_time.convert(epoch, &my_time_zone, &not_used); /* Init my_time_zone */
 
738
  my_system_gmt_sec(&my_time, &my_time_zone, &not_used); /* Init my_time_zone */
758
739
}
759
740
 
760
741
 
809
790
} /* calc_daynr */
810
791
 
811
792
 
812
 
namespace type {
813
793
/*
814
 
  Convert time in type::Time representation in system time zone to its
 
794
  Convert time in DRIZZLE_TIME representation in system time zone to its
815
795
  time_t form (number of seconds in UTC since begginning of Unix Epoch).
816
796
 
817
797
  SYNOPSIS
832
812
  RETURN VALUE
833
813
    Time in UTC seconds since Unix Epoch representation.
834
814
*/
835
 
void Time::convert(epoch_t &epoch, long *my_timezone, bool *in_dst_time_gap, bool skip_timezone) const
 
815
time_t
 
816
my_system_gmt_sec(const DRIZZLE_TIME *t_src, long *my_timezone,
 
817
                  bool *in_dst_time_gap)
836
818
{
837
819
  uint32_t loop;
 
820
  time_t tmp= 0;
838
821
  int shift= 0;
839
 
  type::Time tmp_time;
840
 
  type::Time *t= &tmp_time;
 
822
  DRIZZLE_TIME tmp_time;
 
823
  DRIZZLE_TIME *t= &tmp_time;
841
824
  struct tm *l_time,tm_tmp;
842
825
  long diff, current_timezone;
843
826
 
845
828
    Use temp variable to avoid trashing input data, which could happen in
846
829
    case of shift required for boundary dates processing.
847
830
  */
848
 
  tmp_time= *this;
 
831
  memcpy(&tmp_time, t_src, sizeof(DRIZZLE_TIME));
849
832
 
850
 
  if (not t->isValidEpoch())
851
 
  {
852
 
    epoch= 0;
853
 
    return;
854
 
  }
 
833
  if (!validate_timestamp_range(t))
 
834
    return 0;
855
835
 
856
836
  /*
857
837
    Calculate the gmt time based on current time and timezone
864
844
    We can't use mktime() as it's buggy on many platforms and not thread safe.
865
845
 
866
846
    Note: this code assumes that our time_t estimation is not too far away
867
 
    from real value (we assume that localtime_r(epoch) will return something
 
847
    from real value (we assume that localtime_r(tmp) will return something
868
848
    within 24 hrs from t) which is probably true for all current time zones.
869
849
 
870
850
    Note2: For the dates, which have time_t representation close to
903
883
    We are safe with shifts close to MAX_INT32, as there are no known
904
884
    time switches on Jan 2038 yet :)
905
885
  */
 
886
  if ((t->year == TIMESTAMP_MAX_YEAR) && (t->month == 1) && (t->day > 4))
 
887
  {
 
888
    /*
 
889
      Below we will pass (uint32_t) (t->day - shift) to calc_daynr.
 
890
      As we don't want to get an overflow here, we will shift
 
891
      only safe dates. That's why we have (t->day > 4) above.
 
892
    */
 
893
    t->day-= 2;
 
894
    shift= 2;
 
895
  }
906
896
#ifdef TIME_T_UNSIGNED
 
897
  else
907
898
  {
908
899
    /*
909
900
      We can get 0 in time_t representaion only on 1969, 31 of Dec or on
932
923
  }
933
924
#endif
934
925
 
935
 
  epoch= (type::Time::epoch_t) (((calc_daynr((uint32_t) t->year, (uint32_t) t->month, (uint32_t) t->day) -
 
926
  tmp= (time_t) (((calc_daynr((uint32_t) t->year, (uint32_t) t->month, (uint32_t) t->day) -
936
927
                   (long) days_at_timestart)*86400L + (long) t->hour*3600L +
937
928
                  (long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
938
929
                 3600);
939
930
 
940
931
  current_timezone= my_time_zone;
941
 
  if (skip_timezone)
942
 
  {
943
 
    util::gmtime(epoch, &tm_tmp);
944
 
  }
945
 
  else
946
 
  {
947
 
    util::localtime(epoch, &tm_tmp);
948
 
  }
949
 
 
950
 
  l_time= &tm_tmp;
 
932
  localtime_r(&tmp,&tm_tmp);
 
933
  l_time=&tm_tmp;
951
934
  for (loop=0;
952
935
       loop < 2 &&
953
936
         (t->hour != (uint32_t) l_time->tm_hour ||
965
948
          (long) (60*((int) t->minute - (int) l_time->tm_min)) +
966
949
          (long) ((int) t->second - (int) l_time->tm_sec));
967
950
    current_timezone+= diff+3600;               /* Compensate for -3600 above */
968
 
    epoch+= (time_t) diff;
969
 
    if (skip_timezone)
970
 
    {
971
 
      util::gmtime(epoch, &tm_tmp);
972
 
    }
973
 
    else
974
 
    {
975
 
      util::localtime(epoch, &tm_tmp);
976
 
    }
 
951
    tmp+= (time_t) diff;
 
952
    localtime_r(&tmp,&tm_tmp);
977
953
    l_time=&tm_tmp;
978
954
  }
979
955
  /*
997
973
          (long) (60*((int) t->minute - (int) l_time->tm_min)) +
998
974
          (long) ((int) t->second - (int) l_time->tm_sec));
999
975
    if (diff == 3600)
1000
 
      epoch+=3600 - t->minute*60 - t->second;   /* Move to next hour */
 
976
      tmp+=3600 - t->minute*60 - t->second;     /* Move to next hour */
1001
977
    else if (diff == -3600)
1002
 
      epoch-=t->minute*60 + t->second;          /* Move to previous hour */
 
978
      tmp-=t->minute*60 + t->second;            /* Move to previous hour */
1003
979
 
1004
980
    *in_dst_time_gap= true;
1005
981
  }
1007
983
 
1008
984
 
1009
985
  /* shift back, if we were dealing with boundary dates */
1010
 
  epoch+= shift*86400L;
 
986
  tmp+= shift*86400L;
1011
987
 
1012
988
  /*
1013
989
    This is possible for dates, which slightly exceed boundaries.
1014
990
    Conversion will pass ok for them, but we don't allow them.
1015
991
    First check will pass for platforms with signed time_t.
1016
 
    instruction above (epoch+= shift*86400L) could exceed
 
992
    instruction above (tmp+= shift*86400L) could exceed
1017
993
    MAX_INT32 (== TIMESTAMP_MAX_VALUE) and overflow will happen.
1018
 
    So, epoch < TIMESTAMP_MIN_VALUE will be triggered.
 
994
    So, tmp < TIMESTAMP_MIN_VALUE will be triggered. On platfroms
 
995
    with unsigned time_t tmp+= shift*86400L might result in a number,
 
996
    larger then TIMESTAMP_MAX_VALUE, so another check will work.
1019
997
  */
1020
 
  if (epoch < TIMESTAMP_MIN_VALUE)
1021
 
  {
1022
 
    epoch= 0;
1023
 
  }
 
998
  if ((tmp < TIMESTAMP_MIN_VALUE) || (tmp > TIMESTAMP_MAX_VALUE))
 
999
    tmp= 0;
 
1000
 
 
1001
  return (time_t) tmp;
1024
1002
} /* my_system_gmt_sec */
1025
1003
 
1026
1004
 
1027
 
void Time::store(const struct tm &from)
1028
 
{
1029
 
  _is_local_time= false;
1030
 
  neg= 0;
1031
 
  second_part= 0;
1032
 
  year= (int32_t) ((from.tm_year+1900) % 10000);
1033
 
  month= (int32_t) from.tm_mon+1;
1034
 
  day= (int32_t) from.tm_mday;
1035
 
  hour= (int32_t) from.tm_hour;
1036
 
  minute= (int32_t) from.tm_min;
1037
 
  second= (int32_t) from.tm_sec;
1038
 
 
1039
 
  time_type= DRIZZLE_TIMESTAMP_DATETIME;
1040
 
}
1041
 
 
1042
 
void Time::store(const struct timeval &from)
1043
 
{
1044
 
  store(from.tv_sec, (usec_t)from.tv_usec);
1045
 
  time_type= type::DRIZZLE_TIMESTAMP_DATETIME;
1046
 
}
1047
 
 
1048
 
 
1049
 
void Time::store(const type::Time::epoch_t &from, bool use_localtime)
1050
 
{
1051
 
  store(from, 0, use_localtime);
1052
 
}
1053
 
 
1054
 
void Time::store(const type::Time::epoch_t &from_arg, const usec_t &from_fractional_seconds, bool use_localtime)
1055
 
{
1056
 
  epoch_t from= from_arg;
1057
 
 
1058
 
  if (use_localtime)
1059
 
  {
1060
 
    util::localtime(from, *this);
1061
 
    _is_local_time= true;
1062
 
  }
1063
 
  else
1064
 
  {
1065
 
    util::gmtime(from, *this);
1066
 
  }
1067
 
 
1068
 
  // Since time_t/epoch_t doesn't have fractional seconds, we have to
1069
 
  // collect them outside of the gmtime function.
1070
 
  second_part= from_fractional_seconds;
1071
 
  time_type= DRIZZLE_TIMESTAMP_DATETIME;
1072
 
}
1073
 
 
1074
 
// Only implemented for one case, extend as needed.
1075
 
void Time::truncate(const timestamp_t arg)
1076
 
{
1077
 
  assert(arg == type::DRIZZLE_TIMESTAMP_TIME);
1078
 
  year= month= day= 0;
1079
 
 
1080
 
  time_type= arg;
1081
 
}
1082
 
 
1083
 
void Time::convert(String &str, timestamp_t arg)
1084
 
{
1085
 
  str.alloc(MAX_STRING_LENGTH);
1086
 
  size_t length= MAX_STRING_LENGTH;
1087
 
 
1088
 
  convert(str.c_ptr(), length, arg);
1089
 
 
1090
 
  str.length(length);
1091
 
  str.set_charset(&my_charset_bin);
1092
 
}
1093
 
 
1094
 
void Time::convert(char *str, size_t &to_length, timestamp_t arg)
1095
 
{
1096
 
  int32_t length= 0;
1097
 
  switch (arg) {
 
1005
/* Set DRIZZLE_TIME structure to 0000-00-00 00:00:00.000000 */
 
1006
 
 
1007
void set_zero_time(DRIZZLE_TIME *tm, enum enum_drizzle_timestamp_type time_type)
 
1008
{
 
1009
  memset(tm, 0, sizeof(*tm));
 
1010
  tm->time_type= time_type;
 
1011
}
 
1012
 
 
1013
 
 
1014
/*
 
1015
  Functions to convert time/date/datetime value to a string,
 
1016
  using default format.
 
1017
  This functions don't check that given DRIZZLE_TIME structure members are
 
1018
  in valid range. If they are not, return value won't reflect any
 
1019
  valid date either. Additionally, make_time doesn't take into
 
1020
  account time->day member: it's assumed that days have been converted
 
1021
  to hours already.
 
1022
 
 
1023
  RETURN
 
1024
    number of characters written to 'to'
 
1025
*/
 
1026
 
 
1027
int my_time_to_str(const DRIZZLE_TIME *l_time, char *to)
 
1028
{
 
1029
  uint32_t extra_hours= 0;
 
1030
  return sprintf(to, "%s%02u:%02u:%02u",
 
1031
                         (l_time->neg ? "-" : ""),
 
1032
                         extra_hours+ l_time->hour,
 
1033
                         l_time->minute,
 
1034
                         l_time->second);
 
1035
}
 
1036
 
 
1037
int my_date_to_str(const DRIZZLE_TIME *l_time, char *to)
 
1038
{
 
1039
  return sprintf(to, "%04u-%02u-%02u",
 
1040
                         l_time->year,
 
1041
                         l_time->month,
 
1042
                         l_time->day);
 
1043
}
 
1044
 
 
1045
int my_datetime_to_str(const DRIZZLE_TIME *l_time, char *to)
 
1046
{
 
1047
  return sprintf(to, "%04u-%02u-%02u %02u:%02u:%02u",
 
1048
                         l_time->year,
 
1049
                         l_time->month,
 
1050
                         l_time->day,
 
1051
                         l_time->hour,
 
1052
                         l_time->minute,
 
1053
                         l_time->second);
 
1054
}
 
1055
 
 
1056
 
 
1057
/*
 
1058
  Convert struct DATE/TIME/DATETIME value to string using built-in
 
1059
  MySQL time conversion formats.
 
1060
 
 
1061
  SYNOPSIS
 
1062
    my_TIME_to_string()
 
1063
 
 
1064
  NOTE
 
1065
    The string must have at least MAX_DATE_STRING_REP_LENGTH bytes reserved.
 
1066
*/
 
1067
 
 
1068
int my_TIME_to_str(const DRIZZLE_TIME *l_time, char *to)
 
1069
{
 
1070
  switch (l_time->time_type) {
1098
1071
  case DRIZZLE_TIMESTAMP_DATETIME:
1099
 
    length= snprintf(str, to_length,
1100
 
                     "%04" PRIu32 "-%02" PRIu32 "-%02" PRIu32
1101
 
                     " %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ".%06" PRIu32,
1102
 
                     year,
1103
 
                     month,
1104
 
                     day,
1105
 
                     hour,
1106
 
                     minute,
1107
 
                     second,
1108
 
                     second_part);
1109
 
    break;
1110
 
 
 
1072
    return my_datetime_to_str(l_time, to);
1111
1073
  case DRIZZLE_TIMESTAMP_DATE:
1112
 
    length= snprintf(str, to_length, "%04u-%02u-%02u",
1113
 
                     year,
1114
 
                     month,
1115
 
                     day);
1116
 
    break;
1117
 
 
 
1074
    return my_date_to_str(l_time, to);
1118
1075
  case DRIZZLE_TIMESTAMP_TIME:
1119
 
    {
1120
 
      uint32_t extra_hours= 0;
1121
 
 
1122
 
      length= snprintf(str, to_length,
1123
 
                       "%s%02u:%02u:%02u",
1124
 
                       (neg ? "-" : ""),
1125
 
                       extra_hours+ hour,
1126
 
                       minute,
1127
 
                       second);
1128
 
    }
1129
 
    break;
1130
 
 
 
1076
    return my_time_to_str(l_time, to);
1131
1077
  case DRIZZLE_TIMESTAMP_NONE:
1132
1078
  case DRIZZLE_TIMESTAMP_ERROR:
 
1079
    to[0]='\0';
 
1080
    return 0;
 
1081
  default:
1133
1082
    assert(0);
1134
 
    break;
1135
 
  }
1136
 
 
1137
 
  if (length < 0)
1138
 
  {
1139
 
    to_length= 0;
1140
 
    return;
1141
 
  }
1142
 
 
1143
 
  to_length= length;
1144
 
}
1145
 
 
1146
 
}
 
1083
    return 0;
 
1084
  }
 
1085
}
 
1086
 
1147
1087
 
1148
1088
/*
1149
1089
  Convert datetime value specified as number to broken-down TIME
1153
1093
    number_to_datetime()
1154
1094
      nr         - datetime value as number
1155
1095
      time_res   - pointer for structure for broken-down representation
1156
 
      flags      - flags to use in validating date, as in store()
 
1096
      flags      - flags to use in validating date, as in str_to_datetime()
1157
1097
      was_cut    0      Value ok
1158
1098
                 1      If value was cut during conversion
1159
 
                 2      check(date,flags) considers date invalid
 
1099
                 2      check_date(date,flags) considers date invalid
1160
1100
 
1161
1101
  DESCRIPTION
1162
1102
    Convert a datetime value of formats YYMMDD, YYYYMMDD, YYMMDDHHMSS,
1163
 
    YYYYMMDDHHMMSS to broken-down type::Time representation. Return value in
 
1103
    YYYYMMDDHHMMSS to broken-down DRIZZLE_TIME representation. Return value in
1164
1104
    YYYYMMDDHHMMSS format as side-effect.
1165
1105
 
1166
1106
    This function also checks if datetime value fits in DATETIME range.
1171
1111
    Datetime value in YYYYMMDDHHMMSS format.
1172
1112
*/
1173
1113
 
1174
 
static int64_t number_to_datetime(int64_t nr, type::Time *time_res,
1175
 
                                  uint32_t flags, type::cut_t &was_cut)
 
1114
int64_t number_to_datetime(int64_t nr, DRIZZLE_TIME *time_res,
 
1115
                            uint32_t flags, int *was_cut)
1176
1116
{
1177
1117
  long part1,part2;
1178
1118
 
1179
 
  was_cut= type::VALID;
1180
 
  time_res->reset();
1181
 
  time_res->time_type=type::DRIZZLE_TIMESTAMP_DATE;
 
1119
  *was_cut= 0;
 
1120
  memset(time_res, 0, sizeof(*time_res));
 
1121
  time_res->time_type=DRIZZLE_TIMESTAMP_DATE;
1182
1122
 
1183
1123
  if (nr == 0LL || nr >= 10000101000000LL)
1184
1124
  {
1185
 
    time_res->time_type= type::DRIZZLE_TIMESTAMP_DATETIME;
 
1125
    time_res->time_type=DRIZZLE_TIMESTAMP_DATETIME;
1186
1126
    goto ok;
1187
1127
  }
1188
1128
  if (nr < 101)
1209
1149
  if (nr < 101000000L)
1210
1150
    goto err;
1211
1151
 
1212
 
  time_res->time_type= type::DRIZZLE_TIMESTAMP_DATETIME;
 
1152
  time_res->time_type=DRIZZLE_TIMESTAMP_DATETIME;
1213
1153
 
1214
1154
  if (nr <= (YY_PART_YEAR-1) * 10000000000LL + 1231235959LL)
1215
1155
  {
1234
1174
  if (time_res->year <= 9999 && time_res->month <= 12 &&
1235
1175
      time_res->day <= 31 && time_res->hour <= 23 &&
1236
1176
      time_res->minute <= 59 && time_res->second <= 59 &&
1237
 
      not time_res->check((nr != 0), flags, was_cut))
1238
 
  {
 
1177
      !check_date(time_res, (nr != 0), flags, was_cut))
1239
1178
    return nr;
1240
 
  }
1241
1179
 
1242
1180
  /* Don't want to have was_cut get set if NO_ZERO_DATE was violated. */
1243
1181
  if (!nr && (flags & TIME_NO_ZERO_DATE))
1244
1182
    return -1LL;
1245
1183
 
1246
1184
 err:
1247
 
  was_cut= type::CUT;
 
1185
  *was_cut= 1;
1248
1186
  return -1LL;
1249
1187
}
1250
1188
 
1251
1189
 
1252
 
namespace type {
1253
 
 
1254
 
void Time::convert(datetime_t &ret, int64_t nr, uint32_t flags)
1255
 
{
1256
 
  type::cut_t was_cut;
1257
 
  ret= number_to_datetime(nr, this, flags, was_cut);
1258
 
}
1259
 
 
1260
 
void Time::convert(datetime_t &ret, int64_t nr, uint32_t flags, type::cut_t &was_cut)
1261
 
{
1262
 
  ret= number_to_datetime(nr, this, flags, was_cut);
1263
 
}
1264
 
 
1265
 
/*
1266
 
  Convert struct type::Time (date and time split into year/month/day/hour/...
 
1190
/* Convert time value to integer in YYYYMMDDHHMMSS format */
 
1191
 
 
1192
uint64_t TIME_to_uint64_t_datetime(const DRIZZLE_TIME *my_time)
 
1193
{
 
1194
  return ((uint64_t) (my_time->year * 10000UL +
 
1195
                       my_time->month * 100UL +
 
1196
                       my_time->day) * 1000000ULL +
 
1197
          (uint64_t) (my_time->hour * 10000UL +
 
1198
                       my_time->minute * 100UL +
 
1199
                       my_time->second));
 
1200
}
 
1201
 
 
1202
 
 
1203
/* Convert DRIZZLE_TIME value to integer in YYYYMMDD format */
 
1204
 
 
1205
static uint64_t TIME_to_uint64_t_date(const DRIZZLE_TIME *my_time)
 
1206
{
 
1207
  return (uint64_t) (my_time->year * 10000UL + my_time->month * 100UL +
 
1208
                      my_time->day);
 
1209
}
 
1210
 
 
1211
 
 
1212
/*
 
1213
  Convert DRIZZLE_TIME value to integer in HHMMSS format.
 
1214
  This function doesn't take into account time->day member:
 
1215
  it's assumed that days have been converted to hours already.
 
1216
*/
 
1217
 
 
1218
static uint64_t TIME_to_uint64_t_time(const DRIZZLE_TIME *my_time)
 
1219
{
 
1220
  return (uint64_t) (my_time->hour * 10000UL +
 
1221
                      my_time->minute * 100UL +
 
1222
                      my_time->second);
 
1223
}
 
1224
 
 
1225
 
 
1226
/*
 
1227
  Convert struct DRIZZLE_TIME (date and time split into year/month/day/hour/...
1267
1228
  to a number in format YYYYMMDDHHMMSS (DATETIME),
1268
1229
  YYYYMMDD (DATE)  or HHMMSS (TIME).
 
1230
 
 
1231
  SYNOPSIS
 
1232
    TIME_to_uint64_t()
 
1233
 
 
1234
  DESCRIPTION
 
1235
    The function is used when we need to convert value of time item
 
1236
    to a number if it's used in numeric context, i. e.:
 
1237
    SELECT NOW()+1, CURDATE()+0, CURTIMIE()+0;
 
1238
    SELECT ?+1;
 
1239
 
 
1240
  NOTE
 
1241
    This function doesn't check that given DRIZZLE_TIME structure members are
 
1242
    in valid range. If they are not, return value won't reflect any
 
1243
    valid date either.
1269
1244
*/
1270
1245
 
1271
 
 
1272
 
void Time::convert(datetime_t &datetime, timestamp_t arg)
 
1246
uint64_t TIME_to_uint64_t(const DRIZZLE_TIME *my_time)
1273
1247
{
1274
 
  switch (arg)
1275
 
  {
1276
 
    // Convert to YYYYMMDDHHMMSS format
1277
 
  case type::DRIZZLE_TIMESTAMP_DATETIME:
1278
 
    datetime= ((int64_t) (year * 10000UL + month * 100UL + day) * 1000000ULL +
1279
 
               (int64_t) (hour * 10000UL + minute * 100UL + second));
1280
 
    break;
1281
 
 
1282
 
    // Convert to YYYYMMDD
1283
 
  case type::DRIZZLE_TIMESTAMP_DATE:
1284
 
    datetime= (year * 10000UL + month * 100UL + day);
1285
 
    break;
1286
 
 
1287
 
    // Convert to HHMMSS
1288
 
  case type::DRIZZLE_TIMESTAMP_TIME:
1289
 
    datetime= (hour * 10000UL + minute * 100UL + second);
1290
 
    break;
1291
 
 
1292
 
  case type::DRIZZLE_TIMESTAMP_NONE:
1293
 
  case type::DRIZZLE_TIMESTAMP_ERROR:
1294
 
    datetime= 0;
 
1248
  switch (my_time->time_type) {
 
1249
  case DRIZZLE_TIMESTAMP_DATETIME:
 
1250
    return TIME_to_uint64_t_datetime(my_time);
 
1251
  case DRIZZLE_TIMESTAMP_DATE:
 
1252
    return TIME_to_uint64_t_date(my_time);
 
1253
  case DRIZZLE_TIMESTAMP_TIME:
 
1254
    return TIME_to_uint64_t_time(my_time);
 
1255
  case DRIZZLE_TIMESTAMP_NONE:
 
1256
  case DRIZZLE_TIMESTAMP_ERROR:
 
1257
    return 0ULL;
 
1258
  default:
 
1259
    assert(0);
1295
1260
  }
 
1261
  return 0;
1296
1262
}
1297
1263
 
1298
 
} // namespace type
1299
 
 
1300
1264
} /* namespace drizzled */