~drizzle-trunk/drizzle/development

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