~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to drizzled/my_time.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-10-02 14:17:48 UTC
  • mfrom: (1.1.1 upstream)
  • mto: (2.1.17 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20101002141748-m6vbfbfjhrw1153e
Tags: 2010.09.1802-1
* New upstream release.
* Removed pid-file argument hack.
* Updated GPL-2 address to be new address.
* Directly copy in drizzledump.1 since debian doesn't have sphinx 1.0 yet.
* Link to jquery from libjs-jquery. Add it as a depend.
* Add drizzled.8 symlink to the install files.

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