~drizzle-trunk/drizzle/development

1410.4.2 by Djellel E. Difallah
removing my
1
/* Copyright (C) 2004-2006 MySQL AB
2
3
 This program is free software; you can redistribute it and/or modify
4
 it under the terms of the GNU General Public License as published by
5
 the Free Software Foundation; version 2 of the License.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 GNU General Public License for more details.
11
12
 You should have received a copy of the GNU General Public License
13
 along with this program; if not, write to the Free Software
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
1410.4.2 by Djellel E. Difallah
removing my
15
16
#include "config.h"
17
2032 by Brian Aker
MErge in the include changes.
18
#include "drizzled/type/time.h"
1410.4.2 by Djellel E. Difallah
removing my
19
2088.8.2 by Brian Aker
Switch to internal gmtime
20
#include <drizzled/util/gmtime.h>
21
1410.4.2 by Djellel E. Difallah
removing my
22
#include "drizzled/internal/m_string.h"
23
#include "drizzled/charset_info.h"
24
#include <drizzled/util/test.h>
25
#include "drizzled/definitions.h"
2069.2.2 by Brian Aker
Small refactoring around type::Time
26
#include <drizzled/sql_string.h>
1410.4.2 by Djellel E. Difallah
removing my
27
28
#include <cstdio>
29
#include <algorithm>
30
31
using namespace std;
32
33
namespace drizzled
34
{
35
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
36
static int check_time_range(type::Time *my_time, int *warning);
1410.4.2 by Djellel E. Difallah
removing my
37
38
/* Windows version of localtime_r() is declared in my_ptrhead.h */
39
40
uint64_t log_10_int[20]=
41
{
42
  1, 10, 100, 1000, 10000UL, 100000UL, 1000000UL, 10000000UL,
43
  100000000ULL, 1000000000ULL, 10000000000ULL, 100000000000ULL,
44
  1000000000000ULL, 10000000000000ULL, 100000000000000ULL,
45
  1000000000000000ULL, 10000000000000000ULL, 100000000000000000ULL,
46
  1000000000000000000ULL, 10000000000000000000ULL
47
};
48
49
50
/* Position for YYYY-DD-MM HH-MM-DD.FFFFFF AM in default format */
51
52
static unsigned char internal_format_positions[]=
53
{0, 1, 2, 3, 4, 5, 6, (unsigned char) 255};
54
55
static char time_separator=':';
56
57
static uint32_t const days_at_timestart=719528;	/* daynr at 1970.01.01 */
58
unsigned char days_in_month[]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
59
60
/*
61
  Offset of system time zone from UTC in seconds used to speed up
62
  work of my_system_gmt_sec() function.
63
*/
64
static long my_time_zone=0;
65
66
67
/* Calc days in one year. works with 0 <= year <= 99 */
68
69
uint32_t calc_days_in_year(uint32_t year)
70
{
71
  return ((year & 3) == 0 && (year%100 || (year%400 == 0 && year)) ?
72
          366 : 365);
73
}
74
75
/**
76
  @brief Check datetime value for validity according to flags.
77
78
  @param[in]  ltime          Date to check.
79
  @param[in]  not_zero_date  ltime is not the zero date
80
  @param[in]  flags          flags to check
1410.3.4 by Djellel E. Difallah
update references to old my_'s
81
                             (see str_to_datetime() flags in drizzle_time.h)
1410.4.2 by Djellel E. Difallah
removing my
82
  @param[out] was_cut        set to 2 if value was invalid according to flags.
83
                             (Feb 29 in non-leap etc.)  This remains unchanged
84
                             if value is not invalid.
85
86
  @details Here we assume that year and month is ok!
87
    If month is 0 we allow any date. (This only happens if we allow zero
88
    date parts in str_to_datetime())
89
    Disallow dates with zero year and non-zero month and/or day.
90
91
  @return
92
    0  OK
93
    1  error
94
*/
95
2098.3.4 by Brian Aker
Additional encapsulation of time.
96
static bool check_date(const type::Time *ltime, bool not_zero_date,
97
                       uint32_t flags, int *was_cut)
1410.4.2 by Djellel E. Difallah
removing my
98
{
99
  if (not_zero_date)
100
  {
101
    if ((((flags & TIME_NO_ZERO_IN_DATE) || !(flags & TIME_FUZZY_DATE)) &&
102
         (ltime->month == 0 || ltime->day == 0)) ||
103
        (!(flags & TIME_INVALID_DATES) &&
104
         ltime->month && ltime->day > days_in_month[ltime->month-1] &&
105
         (ltime->month != 2 || calc_days_in_year(ltime->year) != 366 ||
106
          ltime->day != 29)))
107
    {
108
      *was_cut= 2;
109
      return true;
110
    }
111
  }
112
  else if (flags & TIME_NO_ZERO_DATE)
113
  {
114
    /*
115
      We don't set *was_cut here to signal that the problem was a zero date
116
      and not an invalid date
117
    */
118
    return true;
119
  }
120
  return false;
121
}
122
2098.3.4 by Brian Aker
Additional encapsulation of time.
123
namespace type {
124
125
bool Time::check(bool not_zero_date, uint32_t flags, int *was_cut) const
126
{
127
  return check_date(this, not_zero_date, flags, was_cut);
128
}
129
130
} // namespace type
131
1410.4.2 by Djellel E. Difallah
removing my
132
133
/*
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
134
  Convert a timestamp string to a type::Time value.
1410.4.2 by Djellel E. Difallah
removing my
135
136
  SYNOPSIS
137
    str_to_datetime()
138
    str                 String to parse
139
    length              Length of string
140
    l_time              Date is stored here
141
    flags               Bitmap of following items
142
                        TIME_FUZZY_DATE    Set if we should allow partial dates
143
                        TIME_DATETIME_ONLY Set if we only allow full datetimes.
144
                        TIME_NO_ZERO_IN_DATE	Don't allow partial dates
145
                        TIME_NO_ZERO_DATE	Don't allow 0000-00-00 date
146
                        TIME_INVALID_DATES	Allow 2000-02-31
147
    was_cut             0	Value OK
148
			1       If value was cut during conversion
149
			2	check_date(date,flags) considers date invalid
150
151
  DESCRIPTION
152
    At least the following formats are recogniced (based on number of digits)
153
    YYMMDD, YYYYMMDD, YYMMDDHHMMSS, YYYYMMDDHHMMSS
154
    YY-MM-DD, YYYY-MM-DD, YY-MM-DD HH.MM.SS
155
    YYYYMMDDTHHMMSS  where T is a the character T (ISO8601)
156
    Also dates where all parts are zero are allowed
157
158
    The second part may have an optional .###### fraction part.
159
160
  NOTES
161
   This function should work with a format position vector as long as the
162
   following things holds:
163
   - All date are kept together and all time parts are kept together
164
   - Date and time parts must be separated by blank
165
   - Second fractions must come after second part and be separated
166
     by a '.'.  (The second fractions are optional)
167
   - AM/PM must come after second fractions (or after seconds if no fractions)
168
   - Year must always been specified.
169
   - If time is before date, then we will use datetime format only if
170
     the argument consist of two parts, separated by space.
171
     Otherwise we will assume the argument is a date.
172
   - The hour part must be specified in hour-minute-second order.
173
174
  RETURN VALUES
175
    DRIZZLE_TIMESTAMP_NONE        String wasn't a timestamp, like
176
                                [DD [HH:[MM:[SS]]]].fraction.
177
                                l_time is not changed.
178
    DRIZZLE_TIMESTAMP_DATE        DATE string (YY MM and DD parts ok)
179
    DRIZZLE_TIMESTAMP_DATETIME    Full timestamp
180
    DRIZZLE_TIMESTAMP_ERROR       Timestamp with wrong values.
181
                                All elements in l_time is set to 0
182
*/
183
184
#define MAX_DATE_PARTS 8
185
2088.8.9 by Brian Aker
Merge in namespace of enum.
186
type::timestamp_t
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
187
str_to_datetime(const char *str, uint32_t length, type::Time *l_time,
1410.4.2 by Djellel E. Difallah
removing my
188
                uint32_t flags, int *was_cut)
189
{
190
  uint32_t field_length, year_length=4, digits, i, number_of_fields;
191
  uint32_t date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS];
192
  uint32_t add_hours= 0, start_loop;
193
  uint32_t not_zero_date, allow_space;
194
  bool is_internal_format;
195
  const char *pos, *last_field_pos=NULL;
196
  const char *end=str+length;
197
  const unsigned char *format_position;
198
  bool found_delimitier= 0, found_space= 0;
199
  uint32_t frac_pos, frac_len;
200
201
  *was_cut= 0;
202
203
  /* Skip space at start */
204
  for (; str != end && my_isspace(&my_charset_utf8_general_ci, *str) ; str++)
205
    ;
206
  if (str == end || ! my_isdigit(&my_charset_utf8_general_ci, *str))
207
  {
208
    *was_cut= 1;
2088.8.9 by Brian Aker
Merge in namespace of enum.
209
    return(type::DRIZZLE_TIMESTAMP_NONE);
1410.4.2 by Djellel E. Difallah
removing my
210
  }
211
212
  is_internal_format= 0;
213
  /* This has to be changed if want to activate different timestamp formats */
214
  format_position= internal_format_positions;
215
216
  /*
217
    Calculate number of digits in first part.
218
    If length= 8 or >= 14 then year is of format YYYY.
219
    (YYYY-MM-DD,  YYYYMMDD, YYYYYMMDDHHMMSS)
220
  */
221
  for (pos=str;
222
       pos != end && (my_isdigit(&my_charset_utf8_general_ci,*pos) || *pos == 'T');
223
       pos++)
224
    ;
225
226
  digits= (uint32_t) (pos-str);
227
  start_loop= 0;                                /* Start of scan loop */
228
  date_len[format_position[0]]= 0;              /* Length of year field */
229
  if (pos == end || *pos == '.')
230
  {
231
    /* Found date in internal format (only numbers like YYYYMMDD) */
232
    year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
233
    field_length= year_length;
234
    is_internal_format= 1;
235
    format_position= internal_format_positions;
236
  }
237
  else
238
  {
239
    if (format_position[0] >= 3)                /* If year is after HHMMDD */
240
    {
241
      /*
242
        If year is not in first part then we have to determinate if we got
243
        a date field or a datetime field.
244
        We do this by checking if there is two numbers separated by
245
        space in the input.
246
      */
247
      while (pos < end && !my_isspace(&my_charset_utf8_general_ci, *pos))
248
        pos++;
249
      while (pos < end && !my_isdigit(&my_charset_utf8_general_ci, *pos))
250
        pos++;
251
      if (pos == end)
252
      {
253
        if (flags & TIME_DATETIME_ONLY)
254
        {
255
          *was_cut= 1;
2088.8.9 by Brian Aker
Merge in namespace of enum.
256
          return(type::DRIZZLE_TIMESTAMP_NONE);   /* Can't be a full datetime */
1410.4.2 by Djellel E. Difallah
removing my
257
        }
258
        /* Date field.  Set hour, minutes and seconds to 0 */
259
        date[0]= date[1]= date[2]= date[3]= date[4]= 0;
260
        start_loop= 5;                         /* Start with first date part */
261
      }
262
    }
263
264
    field_length= format_position[0] == 0 ? 4 : 2;
265
  }
266
267
  /*
268
    Only allow space in the first "part" of the datetime field and:
269
    - after days, part seconds
270
    - before and after AM/PM (handled by code later)
271
272
    2003-03-03 20:00:20 AM
273
    20:00:20.000000 AM 03-03-2000
274
  */
275
  i= max((uint32_t) format_position[0], (uint32_t) format_position[1]);
276
  set_if_bigger(i, (uint32_t) format_position[2]);
277
  allow_space= ((1 << i) | (1 << format_position[6]));
278
  allow_space&= (1 | 2 | 4 | 8);
279
280
  not_zero_date= 0;
281
  for (i = start_loop;
282
       i < MAX_DATE_PARTS-1 && str != end &&
283
         my_isdigit(&my_charset_utf8_general_ci,*str);
284
       i++)
285
  {
286
    const char *start= str;
287
    uint32_t tmp_value= (uint32_t) (unsigned char) (*str++ - '0');
288
    while (str != end && my_isdigit(&my_charset_utf8_general_ci,str[0]) &&
289
           (!is_internal_format || --field_length))
290
    {
291
      tmp_value=tmp_value*10 + (uint32_t) (unsigned char) (*str - '0');
292
      str++;
293
    }
294
    date_len[i]= (uint32_t) (str - start);
295
    if (tmp_value > 999999)                     /* Impossible date part */
296
    {
297
      *was_cut= 1;
2088.8.9 by Brian Aker
Merge in namespace of enum.
298
      return(type::DRIZZLE_TIMESTAMP_NONE);
1410.4.2 by Djellel E. Difallah
removing my
299
    }
300
    date[i]=tmp_value;
301
    not_zero_date|= tmp_value;
302
303
    /* Length of next field */
304
    field_length= format_position[i+1] == 0 ? 4 : 2;
305
306
    if ((last_field_pos= str) == end)
307
    {
308
      i++;                                      /* Register last found part */
309
      break;
310
    }
311
    /* Allow a 'T' after day to allow CCYYMMDDT type of fields */
312
    if (i == format_position[2] && *str == 'T')
313
    {
314
      str++;                                    /* ISO8601:  CCYYMMDDThhmmss */
315
      continue;
316
    }
317
    if (i == format_position[5])                /* Seconds */
318
    {
319
      if (*str == '.')                          /* Followed by part seconds */
320
      {
321
        str++;
322
        field_length= 6;                        /* 6 digits */
323
      }
324
      continue;
325
    }
326
    while (str != end &&
327
           (my_ispunct(&my_charset_utf8_general_ci,*str) ||
328
            my_isspace(&my_charset_utf8_general_ci,*str)))
329
    {
330
      if (my_isspace(&my_charset_utf8_general_ci,*str))
331
      {
332
        if (!(allow_space & (1 << i)))
333
        {
334
          *was_cut= 1;
2088.8.9 by Brian Aker
Merge in namespace of enum.
335
          return(type::DRIZZLE_TIMESTAMP_NONE);
1410.4.2 by Djellel E. Difallah
removing my
336
        }
337
        found_space= 1;
338
      }
339
      str++;
340
      found_delimitier= 1;                      /* Should be a 'normal' date */
341
    }
342
    /* Check if next position is AM/PM */
343
    if (i == format_position[6])                /* Seconds, time for AM/PM */
344
    {
345
      i++;                                      /* Skip AM/PM part */
346
      if (format_position[7] != 255)            /* If using AM/PM */
347
      {
348
        if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
349
        {
350
          if (str[0] == 'p' || str[0] == 'P')
351
            add_hours= 12;
352
          else if (str[0] != 'a' || str[0] != 'A')
353
            continue;                           /* Not AM/PM */
354
          str+= 2;                              /* Skip AM/PM */
355
          /* Skip space after AM/PM */
356
          while (str != end && my_isspace(&my_charset_utf8_general_ci,*str))
357
            str++;
358
        }
359
      }
360
    }
361
    last_field_pos= str;
362
  }
363
  if (found_delimitier && !found_space && (flags & TIME_DATETIME_ONLY))
364
  {
365
    *was_cut= 1;
2088.8.9 by Brian Aker
Merge in namespace of enum.
366
    return(type::DRIZZLE_TIMESTAMP_NONE);          /* Can't be a datetime */
1410.4.2 by Djellel E. Difallah
removing my
367
  }
368
369
  str= last_field_pos;
370
371
  number_of_fields= i - start_loop;
372
  while (i < MAX_DATE_PARTS)
373
  {
374
    date_len[i]= 0;
375
    date[i++]= 0;
376
  }
377
378
  if (!is_internal_format)
379
  {
380
    year_length= date_len[(uint32_t) format_position[0]];
381
    if (!year_length)                           /* Year must be specified */
382
    {
383
      *was_cut= 1;
2088.8.9 by Brian Aker
Merge in namespace of enum.
384
      return(type::DRIZZLE_TIMESTAMP_NONE);
1410.4.2 by Djellel E. Difallah
removing my
385
    }
386
387
    l_time->year=               date[(uint32_t) format_position[0]];
388
    l_time->month=              date[(uint32_t) format_position[1]];
389
    l_time->day=                date[(uint32_t) format_position[2]];
390
    l_time->hour=               date[(uint32_t) format_position[3]];
391
    l_time->minute=             date[(uint32_t) format_position[4]];
392
    l_time->second=             date[(uint32_t) format_position[5]];
393
394
    frac_pos= (uint32_t) format_position[6];
395
    frac_len= date_len[frac_pos];
396
    if (frac_len < 6)
397
      date[frac_pos]*= (uint32_t) log_10_int[6 - frac_len];
398
    l_time->second_part= date[frac_pos];
399
400
    if (format_position[7] != (unsigned char) 255)
401
    {
402
      if (l_time->hour > 12)
403
      {
404
        *was_cut= 1;
405
        goto err;
406
      }
407
      l_time->hour= l_time->hour%12 + add_hours;
408
    }
409
  }
410
  else
411
  {
412
    l_time->year=       date[0];
413
    l_time->month=      date[1];
414
    l_time->day=        date[2];
415
    l_time->hour=       date[3];
416
    l_time->minute=     date[4];
417
    l_time->second=     date[5];
418
    if (date_len[6] < 6)
419
      date[6]*= (uint32_t) log_10_int[6 - date_len[6]];
420
    l_time->second_part=date[6];
421
  }
422
  l_time->neg= 0;
423
424
  if (year_length == 2 && not_zero_date)
425
    l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);
426
427
  if (number_of_fields < 3 ||
428
      l_time->year > 9999 || l_time->month > 12 ||
429
      l_time->day > 31 || l_time->hour > 23 ||
430
      l_time->minute > 59 || l_time->second > 59)
431
  {
432
    /* Only give warning for a zero date if there is some garbage after */
433
    if (!not_zero_date)                         /* If zero date */
434
    {
435
      for (; str != end ; str++)
436
      {
437
        if (!my_isspace(&my_charset_utf8_general_ci, *str))
438
        {
439
          not_zero_date= 1;                     /* Give warning */
440
          break;
441
        }
442
      }
443
    }
444
    *was_cut= test(not_zero_date);
445
    goto err;
446
  }
447
448
  if (check_date(l_time, not_zero_date != 0, flags, was_cut))
449
    goto err;
450
451
  l_time->time_type= (number_of_fields <= 3 ?
2088.8.9 by Brian Aker
Merge in namespace of enum.
452
                      type::DRIZZLE_TIMESTAMP_DATE : type::DRIZZLE_TIMESTAMP_DATETIME);
1410.4.2 by Djellel E. Difallah
removing my
453
454
  for (; str != end ; str++)
455
  {
456
    if (!my_isspace(&my_charset_utf8_general_ci,*str))
457
    {
458
      *was_cut= 1;
459
      break;
460
    }
461
  }
462
463
  return(l_time->time_type=
2088.8.9 by Brian Aker
Merge in namespace of enum.
464
              (number_of_fields <= 3 ? type::DRIZZLE_TIMESTAMP_DATE :
465
                                       type::DRIZZLE_TIMESTAMP_DATETIME));
1410.4.2 by Djellel E. Difallah
removing my
466
467
err:
2069.2.2 by Brian Aker
Small refactoring around type::Time
468
469
  l_time->reset();
470
2088.8.9 by Brian Aker
Merge in namespace of enum.
471
  return(type::DRIZZLE_TIMESTAMP_ERROR);
1410.4.2 by Djellel E. Difallah
removing my
472
}
473
474
475
/*
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
476
 Convert a time string to a type::Time struct.
1410.4.2 by Djellel E. Difallah
removing my
477
478
  SYNOPSIS
479
   str_to_time()
480
   str                  A string in full TIMESTAMP format or
481
                        [-] DAYS [H]H:MM:SS, [H]H:MM:SS, [M]M:SS, [H]HMMSS,
482
                        [M]MSS or [S]S
483
                        There may be an optional [.second_part] after seconds
484
   length               Length of str
485
   l_time               Store result here
486
   warning              Set DRIZZLE_TIME_WARN_TRUNCATED flag if the input string
487
                        was cut during conversion, and/or
488
                        DRIZZLE_TIME_WARN_OUT_OF_RANGE flag, if the value is
489
                        out of range.
490
491
   NOTES
492
     Because of the extra days argument, this function can only
493
     work with times where the time arguments are in the above order.
494
495
   RETURN
496
     0  ok
497
     1  error
498
*/
499
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
500
bool str_to_time(const char *str, uint32_t length, type::Time *l_time,
1410.4.2 by Djellel E. Difallah
removing my
501
                    int *warning)
502
{
503
  uint32_t date[5];
504
  uint64_t value;
505
  const char *end=str+length, *end_of_days;
506
  bool found_days,found_hours;
507
  uint32_t state;
508
509
  l_time->neg=0;
510
  *warning= 0;
511
  for (; str != end && my_isspace(&my_charset_utf8_general_ci,*str) ; str++)
512
    length--;
513
  if (str != end && *str == '-')
514
  {
515
    l_time->neg=1;
516
    str++;
517
    length--;
518
  }
519
  if (str == end)
2088.8.9 by Brian Aker
Merge in namespace of enum.
520
    return true;
1410.4.2 by Djellel E. Difallah
removing my
521
522
  /* Check first if this is a full TIMESTAMP */
523
  if (length >= 12)
524
  {                                             /* Probably full timestamp */
525
    int was_cut;
2088.8.9 by Brian Aker
Merge in namespace of enum.
526
    type::timestamp_t res= str_to_datetime(str, length, l_time,
527
                                           (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), &was_cut);
528
    if ((int) res >= (int) type::DRIZZLE_TIMESTAMP_ERROR)
1410.4.2 by Djellel E. Difallah
removing my
529
    {
530
      if (was_cut)
531
        *warning|= DRIZZLE_TIME_WARN_TRUNCATED;
2088.8.9 by Brian Aker
Merge in namespace of enum.
532
      return res == type::DRIZZLE_TIMESTAMP_ERROR;
1410.4.2 by Djellel E. Difallah
removing my
533
    }
534
  }
535
536
  /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
537
  for (value=0; str != end && my_isdigit(&my_charset_utf8_general_ci,*str) ; str++)
538
    value=value*10L + (long) (*str - '0');
539
540
  /* Skip all space after 'days' */
541
  end_of_days= str;
542
  for (; str != end && my_isspace(&my_charset_utf8_general_ci, str[0]) ; str++)
543
    ;
544
545
  found_days=found_hours=0;
546
  if ((uint32_t) (end-str) > 1 && str != end_of_days &&
547
      my_isdigit(&my_charset_utf8_general_ci, *str))
548
  {                                             /* Found days part */
549
    date[0]= (uint32_t) value;
550
    state= 1;                                   /* Assume next is hours */
551
    found_days= 1;
552
  }
553
  else if ((end-str) > 1 &&  *str == time_separator &&
554
           my_isdigit(&my_charset_utf8_general_ci, str[1]))
555
  {
556
    date[0]= 0;                                 /* Assume we found hours */
557
    date[1]= (uint32_t) value;
558
    state=2;
559
    found_hours=1;
560
    str++;                                      /* skip ':' */
561
  }
562
  else
563
  {
564
    /* String given as one number; assume HHMMSS format */
565
    date[0]= 0;
566
    date[1]= (uint32_t) (value/10000);
567
    date[2]= (uint32_t) (value/100 % 100);
568
    date[3]= (uint32_t) (value % 100);
569
    state=4;
570
    goto fractional;
571
  }
572
573
  /* Read hours, minutes and seconds */
574
  for (;;)
575
  {
576
    for (value=0; str != end && my_isdigit(&my_charset_utf8_general_ci,*str) ; str++)
577
      value=value*10L + (long) (*str - '0');
578
    date[state++]= (uint32_t) value;
579
    if (state == 4 || (end-str) < 2 || *str != time_separator ||
580
        !my_isdigit(&my_charset_utf8_general_ci,str[1]))
581
      break;
582
    str++;                                      /* Skip time_separator (':') */
583
  }
584
585
  if (state != 4)
586
  {                                             /* Not HH:MM:SS */
587
    /* Fix the date to assume that seconds was given */
588
    if (!found_hours && !found_days)
589
    {
590
      internal::bmove_upp((unsigned char*) (date+4), (unsigned char*) (date+state),
591
                sizeof(long)*(state-1));
592
      memset(date, 0, sizeof(long)*(4-state));
593
    }
594
    else
595
      memset(date+state, 0, sizeof(long)*(4-state));
596
  }
597
598
fractional:
599
  /* Get fractional second part */
600
  if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_utf8_general_ci,str[1]))
601
  {
602
    int field_length= 5;
603
    str++; value=(uint32_t) (unsigned char) (*str - '0');
604
    while (++str != end && my_isdigit(&my_charset_utf8_general_ci, *str))
605
    {
606
      if (field_length-- > 0)
607
        value= value*10 + (uint32_t) (unsigned char) (*str - '0');
608
    }
609
    if (field_length > 0)
610
      value*= (long) log_10_int[field_length];
611
    else if (field_length < 0)
612
      *warning|= DRIZZLE_TIME_WARN_TRUNCATED;
613
    date[4]= (uint32_t) value;
614
  }
615
  else
1999.4.12 by Brian Aker
Adds additional testing, and fixes CAST again.
616
  {
1410.4.2 by Djellel E. Difallah
removing my
617
    date[4]=0;
1999.4.12 by Brian Aker
Adds additional testing, and fixes CAST again.
618
  }
1410.4.2 by Djellel E. Difallah
removing my
619
620
  /* Check for exponent part: E<gigit> | E<sign><digit> */
621
  /* (may occur as result of %g formatting of time value) */
622
  if ((end - str) > 1 &&
623
      (*str == 'e' || *str == 'E') &&
624
      (my_isdigit(&my_charset_utf8_general_ci, str[1]) ||
625
       ((str[1] == '-' || str[1] == '+') &&
626
        (end - str) > 2 &&
627
        my_isdigit(&my_charset_utf8_general_ci, str[2]))))
628
    return 1;
629
630
  if (internal_format_positions[7] != 255)
631
  {
632
    /* Read a possible AM/PM */
633
    while (str != end && my_isspace(&my_charset_utf8_general_ci, *str))
634
      str++;
635
    if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
636
    {
637
      if (str[0] == 'p' || str[0] == 'P')
638
      {
639
        str+= 2;
640
        date[1]= date[1]%12 + 12;
641
      }
642
      else if (str[0] == 'a' || str[0] == 'A')
643
        str+=2;
644
    }
645
  }
646
647
  /* Integer overflow checks */
648
  if (date[0] > UINT_MAX || date[1] > UINT_MAX ||
649
      date[2] > UINT_MAX || date[3] > UINT_MAX ||
650
      date[4] > UINT_MAX)
651
    return 1;
652
653
  l_time->year=         0;                      /* For protocol::store_time */
654
  l_time->month=        0;
655
  l_time->day=          date[0];
656
  l_time->hour=         date[1];
657
  l_time->minute=       date[2];
658
  l_time->second=       date[3];
659
  l_time->second_part=  date[4];
2088.8.9 by Brian Aker
Merge in namespace of enum.
660
  l_time->time_type= type::DRIZZLE_TIMESTAMP_TIME;
1410.4.2 by Djellel E. Difallah
removing my
661
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
662
  /* Check if the value is valid and fits into type::Time range */
1410.4.2 by Djellel E. Difallah
removing my
663
  if (check_time_range(l_time, warning))
1999.4.12 by Brian Aker
Adds additional testing, and fixes CAST again.
664
  {
1410.4.2 by Djellel E. Difallah
removing my
665
    return 1;
1999.4.12 by Brian Aker
Adds additional testing, and fixes CAST again.
666
  }
1410.4.2 by Djellel E. Difallah
removing my
667
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
668
  /* Check if there is garbage at end of the type::Time specification */
1410.4.2 by Djellel E. Difallah
removing my
669
  if (str != end)
670
  {
671
    do
672
    {
673
      if (!my_isspace(&my_charset_utf8_general_ci,*str))
674
      {
675
        *warning|= DRIZZLE_TIME_WARN_TRUNCATED;
676
        break;
677
      }
678
    } while (++str != end);
679
  }
680
  return 0;
681
}
682
683
684
/*
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
685
  Check 'time' value to lie in the type::Time range
1410.4.2 by Djellel E. Difallah
removing my
686
687
  SYNOPSIS:
688
    check_time_range()
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
689
    time     pointer to type::Time value
1410.4.2 by Djellel E. Difallah
removing my
690
    warning  set DRIZZLE_TIME_WARN_OUT_OF_RANGE flag if the value is out of range
691
692
  DESCRIPTION
693
  If the time value lies outside of the range [-838:59:59, 838:59:59],
694
  set it to the closest endpoint of the range and set
695
  DRIZZLE_TIME_WARN_OUT_OF_RANGE flag in the 'warning' variable.
696
697
  RETURN
698
    0        time value is valid, but was possibly truncated
699
    1        time value is invalid
700
*/
701
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
702
static int check_time_range(type::Time *my_time, int *warning)
1410.4.2 by Djellel E. Difallah
removing my
703
{
704
  int64_t hour;
705
706
  if (my_time->minute >= 60 || my_time->second >= 60)
707
    return 1;
708
709
  hour= my_time->hour + (24*my_time->day);
710
  if (hour <= TIME_MAX_HOUR &&
711
      (hour != TIME_MAX_HOUR || my_time->minute != TIME_MAX_MINUTE ||
712
       my_time->second != TIME_MAX_SECOND || !my_time->second_part))
713
    return 0;
714
715
  my_time->day= 0;
716
  my_time->hour= TIME_MAX_HOUR;
717
  my_time->minute= TIME_MAX_MINUTE;
718
  my_time->second= TIME_MAX_SECOND;
719
  my_time->second_part= 0;
720
  *warning|= DRIZZLE_TIME_WARN_OUT_OF_RANGE;
721
  return 0;
722
}
723
724
725
/*
726
  Prepare offset of system time zone from UTC for my_system_gmt_sec() func.
727
728
  SYNOPSIS
729
    init_time()
730
*/
731
void init_time(void)
732
{
733
  time_t seconds;
734
  struct tm *l_time,tm_tmp;
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
735
  type::Time my_time;
1410.4.2 by Djellel E. Difallah
removing my
736
  bool not_used;
737
738
  seconds= (time_t) time((time_t*) 0);
2088.8.5 by Brian Aker
Remove duplicate code around store() for type::Time
739
  localtime_r(&seconds, &tm_tmp);
1410.4.2 by Djellel E. Difallah
removing my
740
  l_time= &tm_tmp;
741
  my_time_zone=		3600;		/* Comp. for -3600 in my_gmt_sec */
742
  my_time.year=		(uint32_t) l_time->tm_year+1900;
743
  my_time.month=	(uint32_t) l_time->tm_mon+1;
744
  my_time.day=		(uint32_t) l_time->tm_mday;
745
  my_time.hour=		(uint32_t) l_time->tm_hour;
746
  my_time.minute=	(uint32_t) l_time->tm_min;
747
  my_time.second=	(uint32_t) l_time->tm_sec;
2088.8.9 by Brian Aker
Merge in namespace of enum.
748
  my_time.time_type=	type::DRIZZLE_TIMESTAMP_NONE;
1410.4.2 by Djellel E. Difallah
removing my
749
  my_time.second_part=  0;
750
  my_time.neg=          false;
751
  my_system_gmt_sec(&my_time, &my_time_zone, &not_used); /* Init my_time_zone */
752
}
753
754
755
/*
756
  Handle 2 digit year conversions
757
758
  SYNOPSIS
759
  year_2000_handling()
760
  year     2 digit year
761
762
  RETURN
763
    Year between 1970-2069
764
*/
765
766
uint32_t year_2000_handling(uint32_t year)
767
{
768
  if ((year=year+1900) < 1900+YY_PART_YEAR)
769
    year+=100;
770
  return year;
771
}
772
773
774
/*
775
  Calculate nr of day since year 0 in new date-system (from 1615)
776
777
  SYNOPSIS
778
    calc_daynr()
779
    year		 Year (exact 4 digit year, no year conversions)
780
    month		 Month
781
    day			 Day
782
783
  NOTES: 0000-00-00 is a valid date, and will return 0
784
785
  RETURN
786
    Days since 0000-00-00
787
*/
788
789
long calc_daynr(uint32_t year,uint32_t month,uint32_t day)
790
{
791
  long delsum;
792
  int temp;
793
794
  if (year == 0 && month == 0 && day == 0)
795
    return(0);				/* Skip errors */
796
  delsum= (long) (365L * year+ 31*(month-1) +day);
797
  if (month <= 2)
798
      year--;
799
  else
800
    delsum-= (long) (month*4+23)/10;
801
  temp=(int) ((year/100+1)*3)/4;
802
  return(delsum+(int) year/4-temp);
803
} /* calc_daynr */
804
805
806
/*
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
807
  Convert time in type::Time representation in system time zone to its
1410.4.2 by Djellel E. Difallah
removing my
808
  time_t form (number of seconds in UTC since begginning of Unix Epoch).
809
810
  SYNOPSIS
811
    my_system_gmt_sec()
812
      t               - time value to be converted
813
      my_timezone     - pointer to long where offset of system time zone
814
                        from UTC will be stored for caching
815
      in_dst_time_gap - set to true if time falls into spring time-gap
816
817
  NOTES
818
    The idea is to cache the time zone offset from UTC (including daylight
819
    saving time) for the next call to make things faster. But currently we
820
    just calculate this offset during startup (by calling init_time()
821
    function) and use it all the time.
822
    Time value provided should be legal time value (e.g. '2003-01-01 25:00:00'
823
    is not allowed).
824
825
  RETURN VALUE
826
    Time in UTC seconds since Unix Epoch representation.
827
*/
2088.8.3 by Brian Aker
Merge in modifications for gmtime to be 64bit on all platforms (that have an
828
type::Time::epoch_t
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
829
my_system_gmt_sec(const type::Time *t_src, long *my_timezone,
2069.2.1 by Brian Aker
Fix issue with now() not storing fractional seconds in timestamp(6)
830
                  bool *in_dst_time_gap, bool skip_timezone)
1410.4.2 by Djellel E. Difallah
removing my
831
{
832
  uint32_t loop;
2088.8.3 by Brian Aker
Merge in modifications for gmtime to be 64bit on all platforms (that have an
833
  type::Time::epoch_t tmp= 0;
1410.4.2 by Djellel E. Difallah
removing my
834
  int shift= 0;
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
835
  type::Time tmp_time;
836
  type::Time *t= &tmp_time;
1410.4.2 by Djellel E. Difallah
removing my
837
  struct tm *l_time,tm_tmp;
838
  long diff, current_timezone;
839
840
  /*
841
    Use temp variable to avoid trashing input data, which could happen in
842
    case of shift required for boundary dates processing.
843
  */
2082.4.2 by Brian Aker
Merge in changes for factor on type::Time
844
  tmp_time= *t_src;
1410.4.2 by Djellel E. Difallah
removing my
845
2082.4.2 by Brian Aker
Merge in changes for factor on type::Time
846
  if (not validate_timestamp_range(t))
1410.4.2 by Djellel E. Difallah
removing my
847
    return 0;
848
849
  /*
850
    Calculate the gmt time based on current time and timezone
851
    The -1 on the end is to ensure that if have a date that exists twice
852
    (like 2002-10-27 02:00:0 MET), we will find the initial date.
853
854
    By doing -3600 we will have to call localtime_r() several times, but
855
    I couldn't come up with a better way to get a repeatable result :(
856
857
    We can't use mktime() as it's buggy on many platforms and not thread safe.
858
859
    Note: this code assumes that our time_t estimation is not too far away
860
    from real value (we assume that localtime_r(tmp) will return something
861
    within 24 hrs from t) which is probably true for all current time zones.
862
863
    Note2: For the dates, which have time_t representation close to
864
    MAX_INT32 (efficient time_t limit for supported platforms), we should
865
    do a small trick to avoid overflow. That is, convert the date, which is
866
    two days earlier, and then add these days to the final value.
867
868
    The same trick is done for the values close to 0 in time_t
869
    representation for platfroms with unsigned time_t (QNX).
870
871
    To be more verbose, here is a sample (extracted from the code below):
872
    (calc_daynr(2038, 1, 19) - (long) days_at_timestart)*86400L + 4*3600L
873
    would return -2147480896 because of the long type overflow. In result
874
    we would get 1901 year in localtime_r(), which is an obvious error.
875
876
    Alike problem raises with the dates close to Epoch. E.g.
877
    (calc_daynr(1969, 12, 31) - (long) days_at_timestart)*86400L + 23*3600L
878
    will give -3600.
879
880
    On some platforms, (E.g. on QNX) time_t is unsigned and localtime(-3600)
881
    wil give us a date around 2106 year. Which is no good.
882
883
    Theoreticaly, there could be problems with the latter conversion:
884
    there are at least two timezones, which had time switches near 1 Jan
885
    of 1970 (because of political reasons). These are America/Hermosillo and
886
    America/Mazatlan time zones. They changed their offset on
887
    1970-01-01 08:00:00 UTC from UTC-8 to UTC-7. For these zones
888
    the code below will give incorrect results for dates close to
889
    1970-01-01, in the case OS takes into account these historical switches.
890
    Luckily, it seems that we support only one platform with unsigned
891
    time_t. It's QNX. And QNX does not support historical timezone data at all.
892
    E.g. there are no /usr/share/zoneinfo/ files or any other mean to supply
893
    historical information for localtime_r() etc. That is, the problem is not
894
    relevant to QNX.
895
896
    We are safe with shifts close to MAX_INT32, as there are no known
897
    time switches on Jan 2038 yet :)
898
  */
899
#ifdef TIME_T_UNSIGNED
900
  {
901
    /*
902
      We can get 0 in time_t representaion only on 1969, 31 of Dec or on
903
      1970, 1 of Jan. For both dates we use shift, which is added
904
      to t->day in order to step out a bit from the border.
905
      This is required for platforms, where time_t is unsigned.
906
      As far as I know, among the platforms we support it's only QNX.
907
      Note: the order of below if-statements is significant.
908
    */
909
910
    if ((t->year == TIMESTAMP_MIN_YEAR + 1) && (t->month == 1)
911
        && (t->day <= 10))
912
    {
913
      t->day+= 2;
914
      shift= -2;
915
    }
916
917
    if ((t->year == TIMESTAMP_MIN_YEAR) && (t->month == 12)
918
        && (t->day == 31))
919
    {
920
      t->year++;
921
      t->month= 1;
922
      t->day= 2;
923
      shift= -2;
924
    }
925
  }
926
#endif
927
2088.8.3 by Brian Aker
Merge in modifications for gmtime to be 64bit on all platforms (that have an
928
  tmp= (type::Time::epoch_t) (((calc_daynr((uint32_t) t->year, (uint32_t) t->month, (uint32_t) t->day) -
1410.4.2 by Djellel E. Difallah
removing my
929
                   (long) days_at_timestart)*86400L + (long) t->hour*3600L +
930
                  (long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
931
                 3600);
932
933
  current_timezone= my_time_zone;
2069.2.1 by Brian Aker
Fix issue with now() not storing fractional seconds in timestamp(6)
934
  if (skip_timezone)
935
  {
2088.8.3 by Brian Aker
Merge in modifications for gmtime to be 64bit on all platforms (that have an
936
    util::gmtime(tmp, &tm_tmp);
2069.2.1 by Brian Aker
Fix issue with now() not storing fractional seconds in timestamp(6)
937
  }
938
  else
939
  {
2088.8.3 by Brian Aker
Merge in modifications for gmtime to be 64bit on all platforms (that have an
940
    util::localtime(tmp, &tm_tmp);
2069.2.1 by Brian Aker
Fix issue with now() not storing fractional seconds in timestamp(6)
941
  }
942
2088.8.3 by Brian Aker
Merge in modifications for gmtime to be 64bit on all platforms (that have an
943
  l_time= &tm_tmp;
1410.4.2 by Djellel E. Difallah
removing my
944
  for (loop=0;
945
       loop < 2 &&
946
	 (t->hour != (uint32_t) l_time->tm_hour ||
947
	  t->minute != (uint32_t) l_time->tm_min ||
948
          t->second != (uint32_t) l_time->tm_sec);
949
       loop++)
950
  {					/* One check should be enough ? */
951
    /* Get difference in days */
952
    int days= t->day - l_time->tm_mday;
953
    if (days < -1)
954
      days= 1;					/* Month has wrapped */
955
    else if (days > 1)
956
      days= -1;
957
    diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) +
958
          (long) (60*((int) t->minute - (int) l_time->tm_min)) +
959
          (long) ((int) t->second - (int) l_time->tm_sec));
960
    current_timezone+= diff+3600;		/* Compensate for -3600 above */
961
    tmp+= (time_t) diff;
2069.2.1 by Brian Aker
Fix issue with now() not storing fractional seconds in timestamp(6)
962
    if (skip_timezone)
963
    {
2088.8.3 by Brian Aker
Merge in modifications for gmtime to be 64bit on all platforms (that have an
964
      util::gmtime(tmp, &tm_tmp);
2069.2.1 by Brian Aker
Fix issue with now() not storing fractional seconds in timestamp(6)
965
    }
966
    else
967
    {
2088.8.3 by Brian Aker
Merge in modifications for gmtime to be 64bit on all platforms (that have an
968
      util::localtime(tmp, &tm_tmp);
2069.2.1 by Brian Aker
Fix issue with now() not storing fractional seconds in timestamp(6)
969
    }
1410.4.2 by Djellel E. Difallah
removing my
970
    l_time=&tm_tmp;
971
  }
972
  /*
973
    Fix that if we are in the non existing daylight saving time hour
974
    we move the start of the next real hour.
975
976
    This code doesn't handle such exotical thing as time-gaps whose length
977
    is more than one hour or non-integer (latter can theoretically happen
978
    if one of seconds will be removed due leap correction, or because of
979
    general time correction like it happened for Africa/Monrovia time zone
980
    in year 1972).
981
  */
982
  if (loop == 2 && t->hour != (uint32_t) l_time->tm_hour)
983
  {
984
    int days= t->day - l_time->tm_mday;
985
    if (days < -1)
986
      days=1;					/* Month has wrapped */
987
    else if (days > 1)
988
      days= -1;
989
    diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour))+
990
	  (long) (60*((int) t->minute - (int) l_time->tm_min)) +
991
          (long) ((int) t->second - (int) l_time->tm_sec));
992
    if (diff == 3600)
993
      tmp+=3600 - t->minute*60 - t->second;	/* Move to next hour */
994
    else if (diff == -3600)
995
      tmp-=t->minute*60 + t->second;		/* Move to previous hour */
996
997
    *in_dst_time_gap= true;
998
  }
999
  *my_timezone= current_timezone;
1000
1001
1002
  /* shift back, if we were dealing with boundary dates */
1003
  tmp+= shift*86400L;
1004
1005
  /*
1006
    This is possible for dates, which slightly exceed boundaries.
1007
    Conversion will pass ok for them, but we don't allow them.
1008
    First check will pass for platforms with signed time_t.
1009
    instruction above (tmp+= shift*86400L) could exceed
1010
    MAX_INT32 (== TIMESTAMP_MAX_VALUE) and overflow will happen.
2082.4.3 by Brian Aker
Updates to time code.
1011
    So, tmp < TIMESTAMP_MIN_VALUE will be triggered.
1410.4.2 by Djellel E. Difallah
removing my
1012
  */
2082.4.3 by Brian Aker
Updates to time code.
1013
  if (tmp < TIMESTAMP_MIN_VALUE)
1014
  {
1410.4.2 by Djellel E. Difallah
removing my
1015
    tmp= 0;
2082.4.3 by Brian Aker
Updates to time code.
1016
  }
1410.4.2 by Djellel E. Difallah
removing my
1017
2088.8.3 by Brian Aker
Merge in modifications for gmtime to be 64bit on all platforms (that have an
1018
  return tmp;
1410.4.2 by Djellel E. Difallah
removing my
1019
} /* my_system_gmt_sec */
1020
1021
1022
/*
1023
  Functions to convert time/date/datetime value to a string,
1024
  using default format.
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
1025
  This functions don't check that given type::Time structure members are
1410.4.2 by Djellel E. Difallah
removing my
1026
  in valid range. If they are not, return value won't reflect any
1027
  valid date either. Additionally, make_time doesn't take into
1028
  account time->day member: it's assumed that days have been converted
1029
  to hours already.
1030
1031
  RETURN
1032
    number of characters written to 'to'
1033
*/
1034
2069.2.2 by Brian Aker
Small refactoring around type::Time
1035
static int my_time_to_str(const type::Time *l_time, char *to)
1410.4.2 by Djellel E. Difallah
removing my
1036
{
2088.8.11 by Brian Aker
Fix additional output, swaps for the valus.
1037
  int32_t length;
1410.4.2 by Djellel E. Difallah
removing my
1038
  uint32_t extra_hours= 0;
2088.8.11 by Brian Aker
Fix additional output, swaps for the valus.
1039
1040
  length= sprintf(to, "%s%02u:%02u:%02u",
1041
                  (l_time->neg ? "-" : ""),
1042
                  extra_hours+ l_time->hour,
1043
                  l_time->minute,
1044
                  l_time->second);
1045
  if (length < 0)
1046
    return 0;
1047
1048
  return static_cast<size_t>(length); 
1410.4.2 by Djellel E. Difallah
removing my
1049
}
1050
2069.2.2 by Brian Aker
Small refactoring around type::Time
1051
static int my_date_to_str(const type::Time *l_time, char *to)
1410.4.2 by Djellel E. Difallah
removing my
1052
{
2088.8.11 by Brian Aker
Fix additional output, swaps for the valus.
1053
  int32_t length;
1054
  length= sprintf(to, "%04u-%02u-%02u",
1410.4.2 by Djellel E. Difallah
removing my
1055
                         l_time->year,
1056
                         l_time->month,
1057
                         l_time->day);
2088.8.11 by Brian Aker
Fix additional output, swaps for the valus.
1058
  if (length < 0)
1059
    return 0;
1060
1061
  return static_cast<size_t>(length); 
1062
}
1063
1064
static size_t my_datetime_to_str(const type::Time *l_time, char *to, size_t to_len)
1065
{
1066
  int32_t length;
1067
  length= snprintf(to, to_len,
1068
                   "%04" PRIu32 "-%02" PRIu32 "-%02" PRIu32
1069
                   " %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ".%06" PRIu32,
1070
                   l_time->year,
1071
                   l_time->month,
1072
                   l_time->day,
1073
                   l_time->hour,
1074
                   l_time->minute,
1075
                   l_time->second,
1076
                   l_time->second_part);
1077
  if (length < 0)
1078
    return 0;
1079
1080
  return static_cast<size_t>(length); 
1081
}
1082
1410.4.2 by Djellel E. Difallah
removing my
1083
2069.2.3 by Brian Aker
Encapsulate a bit more of the logic around making strings from type::Time
1084
namespace type {
1085
2088.8.5 by Brian Aker
Remove duplicate code around store() for type::Time
1086
void Time::store(const struct tm &from)
1087
{
1088
  _is_local_time= false;
1089
  neg= 0;
1090
  second_part= 0;
1091
  year=	(int32_t) ((from.tm_year+1900) % 10000);
1092
  month= (int32_t) from.tm_mon+1;
1093
  day= (int32_t) from.tm_mday;
1094
  hour=	(int32_t) from.tm_hour;
1095
  minute= (int32_t) from.tm_min;
1096
  second= (int32_t) from.tm_sec;
1097
1098
  time_type= DRIZZLE_TIMESTAMP_DATETIME;
1099
}
1100
2088.8.9 by Brian Aker
Merge in namespace of enum.
1101
void Time::store(const struct timeval &from)
1102
{
1103
  store(from.tv_sec, (usec_t)from.tv_usec);
1104
  time_type= type::DRIZZLE_TIMESTAMP_DATETIME;
1105
}
1106
2088.8.5 by Brian Aker
Remove duplicate code around store() for type::Time
1107
2097.1.3 by Brian Aker
Fix header declare.
1108
void Time::store(const type::Time::epoch_t &from, bool use_localtime)
2082.4.2 by Brian Aker
Merge in changes for factor on type::Time
1109
{
1110
  store(from, 0, use_localtime);
1111
}
1112
2097.1.3 by Brian Aker
Fix header declare.
1113
void Time::store(const type::Time::epoch_t &from_arg, const usec_t &from_fractional_seconds, bool use_localtime)
2082.4.2 by Brian Aker
Merge in changes for factor on type::Time
1114
{
2088.8.4 by Brian Aker
Fix storage, skip step, use gmtime.
1115
  epoch_t from= from_arg;
2082.4.2 by Brian Aker
Merge in changes for factor on type::Time
1116
1117
  if (use_localtime)
1118
  {
2088.8.4 by Brian Aker
Fix storage, skip step, use gmtime.
1119
    util::localtime(from, *this);
2082.4.2 by Brian Aker
Merge in changes for factor on type::Time
1120
    _is_local_time= true;
1121
  }
1122
  else
1123
  {
2088.8.4 by Brian Aker
Fix storage, skip step, use gmtime.
1124
    util::gmtime(from, *this);
1125
  }
1126
1127
  // Since time_t/epoch_t doesn't have fractional seconds, we have to
1128
  // collect them outside of the gmtime function.
1129
  second_part= from_fractional_seconds;
2088.8.10 by Brian Aker
Merge in removal of temporal.
1130
  time_type= DRIZZLE_TIMESTAMP_DATETIME;
2082.4.2 by Brian Aker
Merge in changes for factor on type::Time
1131
}
2069.2.3 by Brian Aker
Encapsulate a bit more of the logic around making strings from type::Time
1132
2088.8.9 by Brian Aker
Merge in namespace of enum.
1133
void Time::convert(String &str, timestamp_t arg)
2069.2.3 by Brian Aker
Encapsulate a bit more of the logic around making strings from type::Time
1134
{
2088.8.11 by Brian Aker
Fix additional output, swaps for the valus.
1135
  str.alloc(MAX_STRING_LENGTH);
1136
  size_t length= MAX_STRING_LENGTH;
1137
1138
  convert(str.c_ptr(), length, arg);
1139
1140
  str.length(length);
1141
  str.set_charset(&my_charset_bin);
1142
}
1143
1144
void Time::convert(char *str, size_t &to_length, timestamp_t arg)
1145
{
2069.2.3 by Brian Aker
Encapsulate a bit more of the logic around making strings from type::Time
1146
  switch (arg) {
1147
  case DRIZZLE_TIMESTAMP_DATETIME:
2088.8.11 by Brian Aker
Fix additional output, swaps for the valus.
1148
    to_length= my_datetime_to_str(this, str, to_length);
2069.2.3 by Brian Aker
Encapsulate a bit more of the logic around making strings from type::Time
1149
    break;
1150
1151
  case DRIZZLE_TIMESTAMP_DATE:
2088.8.11 by Brian Aker
Fix additional output, swaps for the valus.
1152
    to_length= (uint32_t) my_date_to_str(this, str);
2069.2.3 by Brian Aker
Encapsulate a bit more of the logic around making strings from type::Time
1153
    break;
1154
1155
  case DRIZZLE_TIMESTAMP_TIME:
2088.8.11 by Brian Aker
Fix additional output, swaps for the valus.
1156
    to_length= (uint32_t) my_time_to_str(this, str);
2098.3.3 by Brian Aker
Isolate out the time code/conversion.
1157
    {
1158
      int32_t length;
1159
      uint32_t extra_hours= 0;
1160
1161
      length= snprintf(str, to_length,
1162
                       "%s%02u:%02u:%02u",
1163
                      (neg ? "-" : ""),
1164
                      extra_hours+ hour,
1165
                      minute,
1166
                      second);
1167
      if (length < 0)
1168
      {
1169
        to_length= 0;
1170
        break;
1171
      }
1172
1173
      to_length= length;
1174
    }
2069.2.3 by Brian Aker
Encapsulate a bit more of the logic around making strings from type::Time
1175
    break;
1176
1177
  case DRIZZLE_TIMESTAMP_NONE:
1178
  case DRIZZLE_TIMESTAMP_ERROR:
1179
    assert(0);
2088.8.11 by Brian Aker
Fix additional output, swaps for the valus.
1180
    to_length= 0;
2069.2.3 by Brian Aker
Encapsulate a bit more of the logic around making strings from type::Time
1181
    break;
1182
  }
1183
}
1184
1185
}
1186
1410.4.2 by Djellel E. Difallah
removing my
1187
/*
1188
  Convert datetime value specified as number to broken-down TIME
1189
  representation and form value of DATETIME type as side-effect.
1190
1191
  SYNOPSIS
1192
    number_to_datetime()
1193
      nr         - datetime value as number
1194
      time_res   - pointer for structure for broken-down representation
1195
      flags      - flags to use in validating date, as in str_to_datetime()
1196
      was_cut    0      Value ok
1197
                 1      If value was cut during conversion
1198
                 2      check_date(date,flags) considers date invalid
1199
1200
  DESCRIPTION
1201
    Convert a datetime value of formats YYMMDD, YYYYMMDD, YYMMDDHHMSS,
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
1202
    YYYYMMDDHHMMSS to broken-down type::Time representation. Return value in
1410.4.2 by Djellel E. Difallah
removing my
1203
    YYYYMMDDHHMMSS format as side-effect.
1204
1205
    This function also checks if datetime value fits in DATETIME range.
1206
1207
  RETURN VALUE
1208
    -1              Timestamp with wrong values
1209
    anything else   DATETIME as integer in YYYYMMDDHHMMSS format
1210
    Datetime value in YYYYMMDDHHMMSS format.
1211
*/
1212
2098.3.3 by Brian Aker
Isolate out the time code/conversion.
1213
static int64_t number_to_datetime(int64_t nr, type::Time *time_res,
1214
                                  uint32_t flags, int *was_cut)
1410.4.2 by Djellel E. Difallah
removing my
1215
{
1216
  long part1,part2;
1217
1218
  *was_cut= 0;
2069.2.2 by Brian Aker
Small refactoring around type::Time
1219
  time_res->reset();
2088.8.9 by Brian Aker
Merge in namespace of enum.
1220
  time_res->time_type=type::DRIZZLE_TIMESTAMP_DATE;
1410.4.2 by Djellel E. Difallah
removing my
1221
1222
  if (nr == 0LL || nr >= 10000101000000LL)
1223
  {
2088.8.9 by Brian Aker
Merge in namespace of enum.
1224
    time_res->time_type= type::DRIZZLE_TIMESTAMP_DATETIME;
1410.4.2 by Djellel E. Difallah
removing my
1225
    goto ok;
1226
  }
1227
  if (nr < 101)
1228
    goto err;
1229
  if (nr <= (YY_PART_YEAR-1)*10000L+1231L)
1230
  {
1231
    nr= (nr+20000000L)*1000000L;                 /* YYMMDD, year: 2000-2069 */
1232
    goto ok;
1233
  }
1234
  if (nr < (YY_PART_YEAR)*10000L+101L)
1235
    goto err;
1236
  if (nr <= 991231L)
1237
  {
1238
    nr= (nr+19000000L)*1000000L;                 /* YYMMDD, year: 1970-1999 */
1239
    goto ok;
1240
  }
1241
  if (nr < 10000101L)
1242
    goto err;
1243
  if (nr <= 99991231L)
1244
  {
1245
    nr= nr*1000000L;
1246
    goto ok;
1247
  }
1248
  if (nr < 101000000L)
1249
    goto err;
1250
2088.8.9 by Brian Aker
Merge in namespace of enum.
1251
  time_res->time_type= type::DRIZZLE_TIMESTAMP_DATETIME;
1410.4.2 by Djellel E. Difallah
removing my
1252
1253
  if (nr <= (YY_PART_YEAR-1) * 10000000000LL + 1231235959LL)
1254
  {
1255
    nr= nr + 20000000000000LL;                   /* YYMMDDHHMMSS, 2000-2069 */
1256
    goto ok;
1257
  }
1258
  if (nr <  YY_PART_YEAR * 10000000000LL + 101000000LL)
1259
    goto err;
1260
  if (nr <= 991231235959LL)
1261
    nr= nr + 19000000000000LL;		/* YYMMDDHHMMSS, 1970-1999 */
1262
1263
 ok:
1264
  part1=(long) (nr / 1000000LL);
1265
  part2=(long) (nr - (int64_t) part1 * 1000000LL);
1266
  time_res->year=  (int) (part1/10000L);  part1%=10000L;
1267
  time_res->month= (int) part1 / 100;
1268
  time_res->day=   (int) part1 % 100;
1269
  time_res->hour=  (int) (part2/10000L);  part2%=10000L;
1270
  time_res->minute=(int) part2 / 100;
1271
  time_res->second=(int) part2 % 100;
1272
1273
  if (time_res->year <= 9999 && time_res->month <= 12 &&
1274
      time_res->day <= 31 && time_res->hour <= 23 &&
1275
      time_res->minute <= 59 && time_res->second <= 59 &&
1276
      !check_date(time_res, (nr != 0), flags, was_cut))
1277
    return nr;
1278
1279
  /* Don't want to have was_cut get set if NO_ZERO_DATE was violated. */
1280
  if (!nr && (flags & TIME_NO_ZERO_DATE))
1281
    return -1LL;
1282
1283
 err:
1284
  *was_cut= 1;
1285
  return -1LL;
1286
}
1287
1288
2098.3.3 by Brian Aker
Isolate out the time code/conversion.
1289
namespace type {
1290
void Time::convert(datetime_t &ret, int64_t nr, uint32_t flags, int *was_cut)
1291
{
1292
  ret= number_to_datetime(nr, this, flags, was_cut);
1293
}
1294
} // namespace type
1295
1296
1410.4.2 by Djellel E. Difallah
removing my
1297
/* Convert time value to integer in YYYYMMDDHHMMSS format */
1298
2098.3.2 by Brian Aker
Merge in uint to int fixes in time type.
1299
static int64_t TIME_to_int64_t_datetime(const type::Time *my_time)
1410.4.2 by Djellel E. Difallah
removing my
1300
{
2098.3.2 by Brian Aker
Merge in uint to int fixes in time type.
1301
  return ((int64_t) (my_time->year * 10000UL +
1302
                     my_time->month * 100UL +
1303
                     my_time->day) * 1000000ULL +
1304
          (int64_t) (my_time->hour * 10000UL +
1305
                     my_time->minute * 100UL +
1306
                     my_time->second));
1410.4.2 by Djellel E. Difallah
removing my
1307
}
1308
1309
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
1310
/* Convert type::Time value to integer in YYYYMMDD format */
1410.4.2 by Djellel E. Difallah
removing my
1311
2098.3.2 by Brian Aker
Merge in uint to int fixes in time type.
1312
static int64_t TIME_to_int64_t_date(const type::Time *my_time)
1410.4.2 by Djellel E. Difallah
removing my
1313
{
2098.3.2 by Brian Aker
Merge in uint to int fixes in time type.
1314
  return (int64_t) (my_time->year * 10000UL +
1315
                    my_time->month * 100UL +
1316
                    my_time->day);
1410.4.2 by Djellel E. Difallah
removing my
1317
}
1318
1319
1320
/*
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
1321
  Convert type::Time value to integer in HHMMSS format.
1410.4.2 by Djellel E. Difallah
removing my
1322
  This function doesn't take into account time->day member:
1323
  it's assumed that days have been converted to hours already.
1324
*/
1325
2098.3.2 by Brian Aker
Merge in uint to int fixes in time type.
1326
static int64_t TIME_to_int64_t_time(const type::Time *my_time)
1410.4.2 by Djellel E. Difallah
removing my
1327
{
2098.3.2 by Brian Aker
Merge in uint to int fixes in time type.
1328
  return (int64_t) (my_time->hour * 10000UL +
1329
                    my_time->minute * 100UL +
1330
                    my_time->second);
1410.4.2 by Djellel E. Difallah
removing my
1331
}
1332
1333
1334
/*
2030.1.5 by Brian Aker
Update for moving DRIZZLE_TIME to type::Time
1335
  Convert struct type::Time (date and time split into year/month/day/hour/...
1410.4.2 by Djellel E. Difallah
removing my
1336
  to a number in format YYYYMMDDHHMMSS (DATETIME),
1337
  YYYYMMDD (DATE)  or HHMMSS (TIME).
1338
*/
1339
2097.1.6 by Brian Aker
Place limits on timestamp (unforunatly)
1340
namespace type {
1341
2098.3.2 by Brian Aker
Merge in uint to int fixes in time type.
1342
void Time::convert(int64_t &datetime, timestamp_t arg)
2097.1.6 by Brian Aker
Place limits on timestamp (unforunatly)
1343
{
1344
  switch (arg)
1345
  {
1346
  case type::DRIZZLE_TIMESTAMP_DATETIME:
2098.3.2 by Brian Aker
Merge in uint to int fixes in time type.
1347
    datetime= TIME_to_int64_t_datetime(this);
2097.1.6 by Brian Aker
Place limits on timestamp (unforunatly)
1348
    break;
1349
1350
  case type::DRIZZLE_TIMESTAMP_DATE:
2098.3.2 by Brian Aker
Merge in uint to int fixes in time type.
1351
    datetime= TIME_to_int64_t_date(this);
2097.1.6 by Brian Aker
Place limits on timestamp (unforunatly)
1352
    break;
1353
1354
  case type::DRIZZLE_TIMESTAMP_TIME:
2098.3.2 by Brian Aker
Merge in uint to int fixes in time type.
1355
    datetime= TIME_to_int64_t_time(this);
2097.1.6 by Brian Aker
Place limits on timestamp (unforunatly)
1356
    break;
1357
1358
  case type::DRIZZLE_TIMESTAMP_NONE:
1359
  case type::DRIZZLE_TIMESTAMP_ERROR:
1360
    datetime= 0;
1361
  }
1362
}
1363
1364
} // namespace type
1365
1410.4.2 by Djellel E. Difallah
removing my
1366
} /* namespace drizzled */