~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/my_time.cc

  • Committer: Mark Atwood
  • Date: 2011-12-28 02:50:31 UTC
  • Revision ID: me@mark.atwood.name-20111228025031-eh4h1zwv4ig88g0i
fix tests/r/basic.result

Show diffs side-by-side

added added

removed removed

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