~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/time.cc

  • Committer: Brian Aker
  • Date: 2009-02-21 00:18:15 UTC
  • Revision ID: brian@tangent.org-20090221001815-x20e8h71e984lvs1
Completion (?) of uint conversion.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
3
 *
4
 
 *  Copyright (C) 2008-2009 Sun Microsystems, Inc.
 
4
 *  Copyright (C) 2008 Sun Microsystems
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License as published by
20
20
 
21
21
/* Functions to handle date and time */
22
22
 
23
 
#include "config.h"
24
 
#include "drizzled/error.h"
25
 
#include "drizzled/util/test.h"
26
 
#include "drizzled/tztime.h"
27
 
#include "drizzled/session.h"
28
 
#include "drizzled/time_functions.h"
29
 
 
30
 
namespace drizzled
31
 
{
 
23
#include <drizzled/server_includes.h>
 
24
#include <drizzled/error.h>
 
25
#include <drizzled/util/test.h>
 
26
#include <drizzled/tztime.h>
 
27
#include <drizzled/session.h>
 
28
#include <drizzled/function/time/get_format.h>
32
29
 
33
30
/* Some functions to calculate dates */
34
31
 
 
32
#ifndef TESTTIME
 
33
 
 
34
/*
 
35
  Name description of interval names used in statements.
 
36
 
 
37
  'interval_type_to_name' is ordered and sorted on interval size and
 
38
  interval complexity.
 
39
  Order of elements in 'interval_type_to_name' should correspond to
 
40
  the order of elements in 'interval_type' enum
 
41
 
 
42
  See also interval_type, interval_names
 
43
*/
 
44
 
 
45
LEX_STRING interval_type_to_name[INTERVAL_LAST] = {
 
46
  { C_STRING_WITH_LEN("YEAR")},
 
47
  { C_STRING_WITH_LEN("QUARTER")},
 
48
  { C_STRING_WITH_LEN("MONTH")},
 
49
  { C_STRING_WITH_LEN("WEEK")},
 
50
  { C_STRING_WITH_LEN("DAY")},
 
51
  { C_STRING_WITH_LEN("HOUR")},
 
52
  { C_STRING_WITH_LEN("MINUTE")},
 
53
  { C_STRING_WITH_LEN("SECOND")},
 
54
  { C_STRING_WITH_LEN("MICROSECOND")},
 
55
  { C_STRING_WITH_LEN("YEAR_MONTH")},
 
56
  { C_STRING_WITH_LEN("DAY_HOUR")},
 
57
  { C_STRING_WITH_LEN("DAY_MINUTE")},
 
58
  { C_STRING_WITH_LEN("DAY_SECOND")},
 
59
  { C_STRING_WITH_LEN("HOUR_MINUTE")},
 
60
  { C_STRING_WITH_LEN("HOUR_SECOND")},
 
61
  { C_STRING_WITH_LEN("MINUTE_SECOND")},
 
62
  { C_STRING_WITH_LEN("DAY_MICROSECOND")},
 
63
  { C_STRING_WITH_LEN("HOUR_MICROSECOND")},
 
64
  { C_STRING_WITH_LEN("MINUTE_MICROSECOND")},
 
65
  { C_STRING_WITH_LEN("SECOND_MICROSECOND")}
 
66
};
 
67
 
 
68
        /* Calc weekday from daynr */
 
69
        /* Returns 0 for monday, 1 for tuesday .... */
35
70
 
36
71
int calc_weekday(long daynr,bool sunday_first_day_of_week)
37
72
{
38
73
  return ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
39
74
}
40
75
 
41
 
 
42
 
uint32_t calc_week(type::Time *l_time, uint32_t week_behaviour, uint32_t *year)
 
76
/*
 
77
  The bits in week_format has the following meaning:
 
78
   WEEK_MONDAY_FIRST (0)  If not set    Sunday is first day of week
 
79
                          If set        Monday is first day of week
 
80
   WEEK_YEAR (1)          If not set    Week is in range 0-53
 
81
 
 
82
        Week 0 is returned for the the last week of the previous year (for
 
83
        a date at start of january) In this case one can get 53 for the
 
84
        first week of next year.  This flag ensures that the week is
 
85
        relevant for the given year. Note that this flag is only
 
86
        releveant if WEEK_JANUARY is not set.
 
87
 
 
88
                          If set         Week is in range 1-53.
 
89
 
 
90
        In this case one may get week 53 for a date in January (when
 
91
        the week is that last week of previous year) and week 1 for a
 
92
        date in December.
 
93
 
 
94
  WEEK_FIRST_WEEKDAY (2)  If not set    Weeks are numbered according
 
95
                                        to ISO 8601:1988
 
96
                          If set        The week that contains the first
 
97
                                        'first-day-of-week' is week 1.
 
98
 
 
99
        ISO 8601:1988 means that if the week containing January 1 has
 
100
        four or more days in the new year, then it is week 1;
 
101
        Otherwise it is the last week of the previous year, and the
 
102
        next week is week 1.
 
103
*/
 
104
 
 
105
uint32_t calc_week(DRIZZLE_TIME *l_time, uint32_t week_behaviour, uint32_t *year)
43
106
{
44
107
  uint32_t days;
45
108
  uint32_t daynr= calc_daynr(l_time->year,l_time->month,l_time->day);
48
111
  bool week_year= test(week_behaviour & WEEK_YEAR);
49
112
  bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
50
113
 
51
 
  uint32_t weekday= calc_weekday(first_daynr, !monday_first);
 
114
  uint32_t weekday=calc_weekday(first_daynr, !monday_first);
52
115
  *year=l_time->year;
53
116
 
54
117
  if (l_time->month == 1 && l_time->day <= 7-weekday)
79
142
  return days/7+1;
80
143
}
81
144
 
 
145
        /* Change a daynr to year, month and day */
 
146
        /* Daynr 0 is returned as date 00.00.00 */
82
147
 
83
 
void get_date_from_daynr(long daynr,
84
 
                         uint32_t *ret_year,
85
 
                         uint32_t *ret_month,
86
 
                                           uint32_t *ret_day)
 
148
void get_date_from_daynr(long daynr,uint32_t *ret_year,uint32_t *ret_month,
 
149
                         uint32_t *ret_day)
87
150
{
88
151
  uint32_t year,temp,leap_day,day_of_year,days_in_year;
89
152
  unsigned char *month_pos;
107
170
    {
108
171
      if (day_of_year > 31+28)
109
172
      {
110
 
        day_of_year--;
111
 
        if (day_of_year == 31+28)
112
 
          leap_day=1;           /* Handle leapyears leapday */
 
173
        day_of_year--;
 
174
        if (day_of_year == 31+28)
 
175
          leap_day=1;           /* Handle leapyears leapday */
113
176
      }
114
177
    }
115
178
    *ret_month=1;
116
179
    for (month_pos= days_in_month ;
117
 
         day_of_year > (uint32_t) *month_pos ;
118
 
         day_of_year-= *(month_pos++), (*ret_month)++)
 
180
         day_of_year > (uint32_t) *month_pos ;
 
181
         day_of_year-= *(month_pos++), (*ret_month)++)
119
182
      ;
120
183
    *ret_year=year;
121
184
    *ret_day=day_of_year+leap_day;
123
186
  return;
124
187
}
125
188
 
126
 
 
127
 
type::timestamp_t str_to_datetime_with_warn(Session *session,
128
 
                                            const char *str, 
129
 
                                            uint32_t length, 
130
 
                                            type::Time *l_time,
131
 
                                            uint32_t flags)
132
 
{
133
 
  type::cut_t was_cut= type::VALID;
134
 
  type::timestamp_t ts_type;
135
 
 
136
 
  ts_type= l_time->store(str, length,
137
 
                         (flags | (session->variables.sql_mode &
138
 
                                   (MODE_INVALID_DATES |
139
 
                                    MODE_NO_ZERO_DATE))),
140
 
                         was_cut);
141
 
  if (was_cut || ts_type <= type::DRIZZLE_TIMESTAMP_ERROR)
142
 
    make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
189
        /* Functions to handle periods */
 
190
 
 
191
uint32_t convert_period_to_month(uint32_t period)
 
192
{
 
193
  uint32_t a,b;
 
194
  if (period == 0)
 
195
    return 0L;
 
196
  if ((a=period/100) < YY_PART_YEAR)
 
197
    a+=2000;
 
198
  else if (a < 100)
 
199
    a+=1900;
 
200
  b=period%100;
 
201
  return a*12+b-1;
 
202
}
 
203
 
 
204
 
 
205
uint32_t convert_month_to_period(uint32_t month)
 
206
{
 
207
  uint32_t year;
 
208
  if (month == 0L)
 
209
    return 0L;
 
210
  if ((year=month/12) < 100)
 
211
  {
 
212
    year+=(year < YY_PART_YEAR) ? 2000 : 1900;
 
213
  }
 
214
  return year*100+month%12+1;
 
215
}
 
216
 
 
217
 
 
218
/*
 
219
  Convert a timestamp string to a DRIZZLE_TIME value and produce a warning
 
220
  if string was truncated during conversion.
 
221
 
 
222
  NOTE
 
223
    See description of str_to_datetime() for more information.
 
224
*/
 
225
 
 
226
enum enum_drizzle_timestamp_type
 
227
str_to_datetime_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
 
228
                          uint32_t flags)
 
229
{
 
230
  int was_cut;
 
231
  Session *session= current_session;
 
232
  enum enum_drizzle_timestamp_type ts_type;
 
233
 
 
234
  ts_type= str_to_datetime(str, length, l_time,
 
235
                           (flags | (session->variables.sql_mode &
 
236
                                     (MODE_INVALID_DATES |
 
237
                                      MODE_NO_ZERO_DATE))),
 
238
                           &was_cut);
 
239
  if (was_cut || ts_type <= DRIZZLE_TIMESTAMP_ERROR)
 
240
    make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
143
241
                                 str, length, ts_type,  NULL);
144
 
 
145
242
  return ts_type;
146
243
}
147
244
 
148
245
 
 
246
/*
 
247
  Convert a datetime from broken-down DRIZZLE_TIME representation to corresponding
 
248
  TIMESTAMP value.
 
249
 
 
250
  SYNOPSIS
 
251
    TIME_to_timestamp()
 
252
      session             - current thread
 
253
      t               - datetime in broken-down representation,
 
254
      in_dst_time_gap - pointer to bool which is set to true if t represents
 
255
                        value which doesn't exists (falls into the spring
 
256
                        time-gap) or to false otherwise.
 
257
 
 
258
  RETURN
 
259
     Number seconds in UTC since start of Unix Epoch corresponding to t.
 
260
     0 - t contains datetime value which is out of TIMESTAMP range.
 
261
 
 
262
*/
 
263
time_t TIME_to_timestamp(Session *session, const DRIZZLE_TIME *t,
 
264
                            bool *in_dst_time_gap)
 
265
{
 
266
  time_t timestamp;
 
267
 
 
268
  *in_dst_time_gap= 0;
 
269
 
 
270
  timestamp= session->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap);
 
271
  if (timestamp)
 
272
  {
 
273
    return timestamp;
 
274
  }
 
275
 
 
276
  /* If we are here we have range error. */
 
277
  return(0);
 
278
}
 
279
 
 
280
 
 
281
/*
 
282
  Convert a time string to a DRIZZLE_TIME struct and produce a warning
 
283
  if string was cut during conversion.
 
284
 
 
285
  NOTE
 
286
    See str_to_time() for more info.
 
287
*/
149
288
bool
150
 
str_to_time_with_warn(Session *session, const char *str, uint32_t length, type::Time *l_time)
 
289
str_to_time_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time)
151
290
{
152
291
  int warning;
153
 
  bool ret_val= l_time->store(str, length, warning, type::DRIZZLE_TIMESTAMP_TIME);
 
292
  bool ret_val= str_to_time(str, length, l_time, &warning);
154
293
  if (ret_val || warning)
155
 
    make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
156
 
                                 str, length, type::DRIZZLE_TIMESTAMP_TIME, NULL);
 
294
    make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
295
                                 str, length, DRIZZLE_TIMESTAMP_TIME, NULL);
157
296
  return ret_val;
158
297
}
159
298
 
160
299
 
161
 
void make_truncated_value_warning(Session *session, 
162
 
                                  DRIZZLE_ERROR::enum_warning_level level,
 
300
/*
 
301
  Convert a system time structure to TIME
 
302
*/
 
303
 
 
304
void localtime_to_TIME(DRIZZLE_TIME *to, struct tm *from)
 
305
{
 
306
  to->neg=0;
 
307
  to->second_part=0;
 
308
  to->year=     (int) ((from->tm_year+1900) % 10000);
 
309
  to->month=    (int) from->tm_mon+1;
 
310
  to->day=      (int) from->tm_mday;
 
311
  to->hour=     (int) from->tm_hour;
 
312
  to->minute=   (int) from->tm_min;
 
313
  to->second=   (int) from->tm_sec;
 
314
}
 
315
 
 
316
void calc_time_from_sec(DRIZZLE_TIME *to, long seconds, long microseconds)
 
317
{
 
318
  long t_seconds;
 
319
  // to->neg is not cleared, it may already be set to a useful value
 
320
  to->time_type= DRIZZLE_TIMESTAMP_TIME;
 
321
  to->year= 0;
 
322
  to->month= 0;
 
323
  to->day= 0;
 
324
  to->hour= seconds/3600L;
 
325
  t_seconds= seconds%3600L;
 
326
  to->minute= t_seconds/60L;
 
327
  to->second= t_seconds%60L;
 
328
  to->second_part= microseconds;
 
329
}
 
330
 
 
331
 
 
332
/*
 
333
  Parse a format string specification
 
334
 
 
335
  SYNOPSIS
 
336
    parse_date_time_format()
 
337
    format_type         Format of string (time, date or datetime)
 
338
    format_str          String to parse
 
339
    format_length       Length of string
 
340
    date_time_format    Format to fill in
 
341
 
 
342
  NOTES
 
343
    Fills in date_time_format->positions for all date time parts.
 
344
 
 
345
    positions marks the position for a datetime element in the format string.
 
346
    The position array elements are in the following order:
 
347
    YYYY-DD-MM HH-MM-DD.FFFFFF AM
 
348
    0    1  2  3  4  5  6      7
 
349
 
 
350
    If positions[0]= 5, it means that year will be the forth element to
 
351
    read from the parsed date string.
 
352
 
 
353
  RETURN
 
354
    0   ok
 
355
    1   error
 
356
*/
 
357
 
 
358
bool parse_date_time_format(enum enum_drizzle_timestamp_type format_type,
 
359
                            const char *format, uint32_t format_length,
 
360
                            DATE_TIME_FORMAT *date_time_format)
 
361
{
 
362
  uint32_t offset= 0, separators= 0;
 
363
  const char *ptr= format, *format_str;
 
364
  const char *end= ptr+format_length;
 
365
  unsigned char *dt_pos= date_time_format->positions;
 
366
  /* need_p is set if we are using AM/PM format */
 
367
  bool need_p= 0, allow_separator= 0;
 
368
  uint32_t part_map= 0, separator_map= 0;
 
369
  const char *parts[16];
 
370
 
 
371
  date_time_format->time_separator= 0;
 
372
  date_time_format->flag= 0;                    // For future
 
373
 
 
374
  /*
 
375
    Fill position with 'dummy' arguments to found out if a format tag is
 
376
    used twice (This limit's the format to 255 characters, but this is ok)
 
377
  */
 
378
  dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]=
 
379
    dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= 255;
 
380
 
 
381
  for (; ptr != end; ptr++)
 
382
  {
 
383
    if (*ptr == '%' && ptr+1 != end)
 
384
    {
 
385
      uint32_t position;
 
386
      switch (*++ptr) {
 
387
      case 'y':                                 // Year
 
388
      case 'Y':
 
389
        position= 0;
 
390
        break;
 
391
      case 'c':                                 // Month
 
392
      case 'm':
 
393
        position= 1;
 
394
        break;
 
395
      case 'd':
 
396
      case 'e':
 
397
        position= 2;
 
398
        break;
 
399
      case 'h':
 
400
      case 'I':
 
401
      case 'l':
 
402
        need_p= 1;                              // Need AM/PM
 
403
        /* Fall through */
 
404
      case 'k':
 
405
      case 'H':
 
406
        position= 3;
 
407
        break;
 
408
      case 'i':
 
409
        position= 4;
 
410
        break;
 
411
      case 's':
 
412
      case 'S':
 
413
        position= 5;
 
414
        break;
 
415
      case 'f':
 
416
        position= 6;
 
417
        if (dt_pos[5] != offset-1 || ptr[-2] != '.')
 
418
          return 1;                             // Wrong usage of %f
 
419
        break;
 
420
      case 'p':                                 // AM/PM
 
421
        if (offset == 0)                        // Can't be first
 
422
          return 0;
 
423
        position= 7;
 
424
        break;
 
425
      default:
 
426
        return 1;                               // Unknown controll char
 
427
      }
 
428
      if (dt_pos[position] != 255)              // Don't allow same tag twice
 
429
        return 1;
 
430
      parts[position]= ptr-1;
 
431
 
 
432
      /*
 
433
        If switching from time to date, ensure that all time parts
 
434
        are used
 
435
      */
 
436
      if (part_map && position <= 2 && !(part_map & (1 | 2 | 4)))
 
437
        offset=5;
 
438
      part_map|= UINT32_C(1) << position;
 
439
      dt_pos[position]= offset++;
 
440
      allow_separator= 1;
 
441
    }
 
442
    else
 
443
    {
 
444
      /*
 
445
        Don't allow any characters in format as this could easily confuse
 
446
        the date reader
 
447
      */
 
448
      if (!allow_separator)
 
449
        return 1;                               // No separator here
 
450
      allow_separator= 0;                       // Don't allow two separators
 
451
      separators++;
 
452
      /* Store in separator_map which parts are punct characters */
 
453
      if (my_ispunct(&my_charset_utf8_general_ci, *ptr))
 
454
        separator_map|= 1 << (offset-1);
 
455
      else if (!my_isspace(&my_charset_utf8_general_ci, *ptr))
 
456
        return 1;
 
457
    }
 
458
  }
 
459
 
 
460
  /* If no %f, specify it after seconds.  Move %p up, if necessary */
 
461
  if ((part_map & 32) && !(part_map & 64))
 
462
  {
 
463
    dt_pos[6]= dt_pos[5] +1;
 
464
    parts[6]= parts[5];                         // For later test in (need_p)
 
465
    if (dt_pos[6] == dt_pos[7])                 // Move %p one step up if used
 
466
      dt_pos[7]++;
 
467
  }
 
468
 
 
469
  /*
 
470
    Check that we have not used a non legal format specifier and that all
 
471
    format specifiers have been used
 
472
 
 
473
    The last test is to ensure that %p is used if and only if
 
474
    it's needed.
 
475
  */
 
476
  if ((format_type == DRIZZLE_TIMESTAMP_DATETIME &&
 
477
       !test_all_bits(part_map, (uint32_t) (1 | 2 | 4 | 8 | 16 | 32))) ||
 
478
      (format_type == DRIZZLE_TIMESTAMP_DATE && part_map != (1 | 2 | 4)) ||
 
479
      (format_type == DRIZZLE_TIMESTAMP_TIME &&
 
480
       !test_all_bits(part_map, (uint32_t) (8 | 16 | 32))) ||
 
481
      !allow_separator ||                       // %option should be last
 
482
      (need_p && dt_pos[6] +1 != dt_pos[7]) ||
 
483
      (need_p ^ (dt_pos[7] != 255)))
 
484
    return 1;
 
485
 
 
486
  if (dt_pos[6] != 255)                         // If fractional seconds
 
487
  {
 
488
    /* remove fractional seconds from later tests */
 
489
    uint32_t pos= dt_pos[6] -1;
 
490
    /* Remove separator before %f from sep map */
 
491
    separator_map= ((separator_map & ((1 << pos)-1)) |
 
492
                    ((separator_map & ~((1 << pos)-1)) >> 1));
 
493
    if (part_map & 64)
 
494
    {
 
495
      separators--;                             // There is always a separator
 
496
      need_p= 1;                                // force use of separators
 
497
    }
 
498
  }
 
499
 
 
500
  /*
 
501
    Remove possible separator before %p from sep_map
 
502
    (This can either be at position 3, 4, 6 or 7) h.m.d.%f %p
 
503
  */
 
504
  if (dt_pos[7] != 255)
 
505
  {
 
506
    if (need_p && parts[7] != parts[6]+2)
 
507
      separators--;
 
508
  }
 
509
  /*
 
510
    Calculate if %p is in first or last part of the datetime field
 
511
 
 
512
    At this point we have either %H-%i-%s %p 'year parts' or
 
513
    'year parts' &H-%i-%s %p" as %f was removed above
 
514
  */
 
515
  offset= dt_pos[6] <= 3 ? 3 : 6;
 
516
  /* Remove separator before %p from sep map */
 
517
  separator_map= ((separator_map & ((1 << offset)-1)) |
 
518
                  ((separator_map & ~((1 << offset)-1)) >> 1));
 
519
 
 
520
  format_str= 0;
 
521
  switch (format_type) {
 
522
  case DRIZZLE_TIMESTAMP_DATE:
 
523
    format_str= known_date_time_formats[INTERNAL_FORMAT].date_format;
 
524
    /* fall through */
 
525
  case DRIZZLE_TIMESTAMP_TIME:
 
526
    if (!format_str)
 
527
      format_str=known_date_time_formats[INTERNAL_FORMAT].time_format;
 
528
 
 
529
    /*
 
530
      If there is no separators, allow the internal format as we can read
 
531
      this.  If separators are used, they must be between each part
 
532
    */
 
533
    if (format_length == 6 && !need_p &&
 
534
        !my_strnncoll(&my_charset_bin,
 
535
                      (const unsigned char *) format, 6,
 
536
                      (const unsigned char *) format_str, 6))
 
537
      return 0;
 
538
    if (separator_map == (1 | 2))
 
539
    {
 
540
      if (format_type == DRIZZLE_TIMESTAMP_TIME)
 
541
      {
 
542
        if (*(format+2) != *(format+5))
 
543
          break;                                // Error
 
544
        /* Store the character used for time formats */
 
545
        date_time_format->time_separator= *(format+2);
 
546
      }
 
547
      return 0;
 
548
    }
 
549
    break;
 
550
  case DRIZZLE_TIMESTAMP_DATETIME:
 
551
    /*
 
552
      If there is no separators, allow the internal format as we can read
 
553
      this.  If separators are used, they must be between each part.
 
554
      Between DATE and TIME we also allow space as separator
 
555
    */
 
556
    if ((format_length == 12 && !need_p &&
 
557
         !my_strnncoll(&my_charset_bin,
 
558
                       (const unsigned char *) format, 12,
 
559
                       (const unsigned char*) known_date_time_formats[INTERNAL_FORMAT].datetime_format,
 
560
                       12)) ||
 
561
        (separators == 5 && separator_map == (1 | 2 | 8 | 16)))
 
562
      return 0;
 
563
    break;
 
564
  default:
 
565
    assert(1);
 
566
    break;
 
567
  }
 
568
  return 1;                                     // Error
 
569
}
 
570
 
 
571
 
 
572
/*
 
573
  Create a DATE_TIME_FORMAT object from a format string specification
 
574
 
 
575
  SYNOPSIS
 
576
    date_time_format_make()
 
577
    format_type         Format to parse (time, date or datetime)
 
578
    format_str          String to parse
 
579
    format_length       Length of string
 
580
 
 
581
  NOTES
 
582
    The returned object should be freed with free()
 
583
 
 
584
  RETURN
 
585
    NULL ponter:        Error
 
586
    new object
 
587
*/
 
588
 
 
589
DATE_TIME_FORMAT
 
590
*date_time_format_make(enum enum_drizzle_timestamp_type format_type,
 
591
                       const char *format_str, uint32_t format_length)
 
592
{
 
593
  DATE_TIME_FORMAT tmp;
 
594
 
 
595
  if (format_length && format_length < 255 &&
 
596
      !parse_date_time_format(format_type, format_str,
 
597
                              format_length, &tmp))
 
598
  {
 
599
    tmp.format.str=    (char*) format_str;
 
600
    tmp.format.length= format_length;
 
601
    return date_time_format_copy((Session *)0, &tmp);
 
602
  }
 
603
  return 0;
 
604
}
 
605
 
 
606
 
 
607
/*
 
608
  Create a copy of a DATE_TIME_FORMAT object
 
609
 
 
610
  SYNOPSIS
 
611
    date_and_time_format_copy()
 
612
    session                     Set if variable should be allocated in thread mem
 
613
    format              format to copy
 
614
 
 
615
  NOTES
 
616
    The returned object should be freed with free()
 
617
 
 
618
  RETURN
 
619
    NULL ponter:        Error
 
620
    new object
 
621
*/
 
622
 
 
623
DATE_TIME_FORMAT *date_time_format_copy(Session *session, DATE_TIME_FORMAT *format)
 
624
{
 
625
  DATE_TIME_FORMAT *new_format;
 
626
  uint32_t length= sizeof(*format) + format->format.length + 1;
 
627
 
 
628
  if (session)
 
629
    new_format= (DATE_TIME_FORMAT *) session->alloc(length);
 
630
  else
 
631
    new_format=  (DATE_TIME_FORMAT *) malloc(length);
 
632
  if (new_format)
 
633
  {
 
634
    /* Put format string after current pos */
 
635
    new_format->format.str= (char*) (new_format+1);
 
636
    memcpy(new_format->positions, format->positions,
 
637
           sizeof(format->positions));
 
638
    new_format->time_separator= format->time_separator;
 
639
    /* We make the string null terminated for easy printf in SHOW VARIABLES */
 
640
    memcpy(new_format->format.str, format->format.str,
 
641
           format->format.length);
 
642
    new_format->format.str[format->format.length]= 0;
 
643
    new_format->format.length= format->format.length;
 
644
  }
 
645
  return new_format;
 
646
}
 
647
 
 
648
 
 
649
KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]=
 
650
{
 
651
  {"USA", "%m.%d.%Y", "%Y-%m-%d %H.%i.%s", "%h:%i:%s %p" },
 
652
  {"JIS", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
 
653
  {"ISO", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
 
654
  {"EUR", "%d.%m.%Y", "%Y-%m-%d %H.%i.%s", "%H.%i.%s" },
 
655
  {"INTERNAL", "%Y%m%d",   "%Y%m%d%H%i%s", "%H%i%s" },
 
656
  { 0, 0, 0, 0 }
 
657
};
 
658
 
 
659
 
 
660
/*
 
661
   Return format string according format name.
 
662
   If name is unknown, result is NULL
 
663
*/
 
664
 
 
665
const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
 
666
                                     enum enum_drizzle_timestamp_type type)
 
667
{
 
668
  switch (type) {
 
669
  case DRIZZLE_TIMESTAMP_DATE:
 
670
    return format->date_format;
 
671
  case DRIZZLE_TIMESTAMP_DATETIME:
 
672
    return format->datetime_format;
 
673
  case DRIZZLE_TIMESTAMP_TIME:
 
674
    return format->time_format;
 
675
  default:
 
676
    assert(0);                          // Impossible
 
677
    return 0;
 
678
  }
 
679
}
 
680
 
 
681
/****************************************************************************
 
682
  Functions to create default time/date/datetime strings
 
683
 
 
684
  NOTE:
 
685
    For the moment the DATE_TIME_FORMAT argument is ignored becasue
 
686
    MySQL doesn't support comparing of date/time/datetime strings that
 
687
    are not in arbutary order as dates are compared as strings in some
 
688
    context)
 
689
    This functions don't check that given DRIZZLE_TIME structure members are
 
690
    in valid range. If they are not, return value won't reflect any
 
691
    valid date either. Additionally, make_time doesn't take into
 
692
    account time->day member: it's assumed that days have been converted
 
693
    to hours already.
 
694
****************************************************************************/
 
695
 
 
696
void make_time(const DATE_TIME_FORMAT *,
 
697
               const DRIZZLE_TIME *l_time, String *str)
 
698
{
 
699
  uint32_t length= (uint32_t) my_time_to_str(l_time, (char*) str->ptr());
 
700
  str->length(length);
 
701
  str->set_charset(&my_charset_bin);
 
702
}
 
703
 
 
704
 
 
705
void make_date(const DATE_TIME_FORMAT *,
 
706
               const DRIZZLE_TIME *l_time, String *str)
 
707
{
 
708
  uint32_t length= (uint32_t) my_date_to_str(l_time, (char*) str->ptr());
 
709
  str->length(length);
 
710
  str->set_charset(&my_charset_bin);
 
711
}
 
712
 
 
713
 
 
714
void make_datetime(const DATE_TIME_FORMAT *,
 
715
                   const DRIZZLE_TIME *l_time, String *str)
 
716
{
 
717
  uint32_t length= (uint32_t) my_datetime_to_str(l_time, (char*) str->ptr());
 
718
  str->length(length);
 
719
  str->set_charset(&my_charset_bin);
 
720
}
 
721
 
 
722
 
 
723
void make_truncated_value_warning(Session *session, DRIZZLE_ERROR::enum_warning_level level,
163
724
                                  const char *str_val,
164
 
                                                          uint32_t str_length,
165
 
                                  type::timestamp_t time_type,
 
725
                                  uint32_t str_length,
 
726
                                  enum enum_drizzle_timestamp_type time_type,
166
727
                                  const char *field_name)
167
728
{
168
729
  char warn_buff[DRIZZLE_ERRMSG_SIZE];
174
735
  str[str_length]= 0;               // Ensure we have end 0 for snprintf
175
736
 
176
737
  switch (time_type) {
177
 
  case type::DRIZZLE_TIMESTAMP_DATE:
178
 
    type_str= "date";
179
 
    break;
180
 
 
181
 
  case type::DRIZZLE_TIMESTAMP_TIME:
182
 
    type_str= "time";
183
 
    break;
184
 
 
185
 
  case type::DRIZZLE_TIMESTAMP_DATETIME:  // FALLTHROUGH
186
 
  default:
187
 
    type_str= "datetime";
188
 
    break;
 
738
    case DRIZZLE_TIMESTAMP_DATE:
 
739
      type_str= "date";
 
740
      break;
 
741
    case DRIZZLE_TIMESTAMP_TIME:
 
742
      type_str= "time";
 
743
      break;
 
744
    case DRIZZLE_TIMESTAMP_DATETIME:  // FALLTHROUGH
 
745
    default:
 
746
      type_str= "datetime";
 
747
      break;
189
748
  }
190
 
 
191
749
  if (field_name)
192
 
  {
193
750
    cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
194
751
                       ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
195
752
                       type_str, str.c_ptr(), field_name,
196
753
                       (uint32_t) session->row_count);
197
 
  }
198
754
  else
199
755
  {
200
 
    if (time_type > type::DRIZZLE_TIMESTAMP_ERROR)
201
 
    {
 
756
    if (time_type > DRIZZLE_TIMESTAMP_ERROR)
202
757
      cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
203
758
                         ER(ER_TRUNCATED_WRONG_VALUE),
204
759
                         type_str, str.c_ptr());
205
 
    }
206
760
    else
207
 
    {
208
761
      cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
209
762
                         ER(ER_WRONG_VALUE), type_str, str.c_ptr());
210
 
    }
211
763
  }
212
764
  push_warning(session, level,
213
765
               ER_TRUNCATED_WRONG_VALUE, warn_buff);
214
766
}
215
767
 
 
768
bool date_add_interval(DRIZZLE_TIME *ltime, interval_type int_type, INTERVAL interval)
 
769
{
 
770
  long period, sign;
 
771
 
 
772
  ltime->neg= 0;
 
773
 
 
774
  sign= (interval.neg ? -1 : 1);
 
775
 
 
776
  switch (int_type) {
 
777
  case INTERVAL_SECOND:
 
778
  case INTERVAL_SECOND_MICROSECOND:
 
779
  case INTERVAL_MICROSECOND:
 
780
  case INTERVAL_MINUTE:
 
781
  case INTERVAL_HOUR:
 
782
  case INTERVAL_MINUTE_MICROSECOND:
 
783
  case INTERVAL_MINUTE_SECOND:
 
784
  case INTERVAL_HOUR_MICROSECOND:
 
785
  case INTERVAL_HOUR_SECOND:
 
786
  case INTERVAL_HOUR_MINUTE:
 
787
  case INTERVAL_DAY_MICROSECOND:
 
788
  case INTERVAL_DAY_SECOND:
 
789
  case INTERVAL_DAY_MINUTE:
 
790
  case INTERVAL_DAY_HOUR:
 
791
  {
 
792
    int64_t sec, days, daynr, microseconds, extra_sec;
 
793
    ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME; // Return full date
 
794
    microseconds= ltime->second_part + sign*interval.second_part;
 
795
    extra_sec= microseconds/1000000L;
 
796
    microseconds= microseconds%1000000L;
 
797
 
 
798
    sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
 
799
         ltime->second +
 
800
         sign* (int64_t) (interval.day*3600*24L +
 
801
                           interval.hour*3600L+interval.minute*60L+
 
802
                           interval.second))+ extra_sec;
 
803
    if (microseconds < 0)
 
804
    {
 
805
      microseconds+= 1000000L;
 
806
      sec--;
 
807
    }
 
808
    days= sec/(3600*24L);
 
809
    sec-= days*3600*24L;
 
810
    if (sec < 0)
 
811
    {
 
812
      days--;
 
813
      sec+= 3600*24L;
 
814
    }
 
815
    ltime->second_part= (uint32_t) microseconds;
 
816
    ltime->second= (uint32_t) (sec % 60);
 
817
    ltime->minute= (uint32_t) (sec/60 % 60);
 
818
    ltime->hour=   (uint32_t) (sec/3600);
 
819
    daynr= calc_daynr(ltime->year,ltime->month,1) + days;
 
820
    /* Day number from year 0 to 9999-12-31 */
 
821
    if ((uint64_t) daynr > MAX_DAY_NUMBER)
 
822
      goto invalid_date;
 
823
    get_date_from_daynr((long) daynr, &ltime->year, &ltime->month,
 
824
                        &ltime->day);
 
825
    break;
 
826
  }
 
827
  case INTERVAL_DAY:
 
828
  case INTERVAL_WEEK:
 
829
    period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
 
830
             sign * (long) interval.day);
 
831
    /* Daynumber from year 0 to 9999-12-31 */
 
832
    if (period > MAX_DAY_NUMBER)
 
833
      goto invalid_date;
 
834
    get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
 
835
    break;
 
836
  case INTERVAL_YEAR:
 
837
    ltime->year+= sign * (long) interval.year;
 
838
    if (ltime->year >= 10000L)
 
839
      goto invalid_date;
 
840
    if (ltime->month == 2 && ltime->day == 29 &&
 
841
        calc_days_in_year(ltime->year) != 366)
 
842
      ltime->day=28;                            // Was leap-year
 
843
    break;
 
844
  case INTERVAL_YEAR_MONTH:
 
845
  case INTERVAL_QUARTER:
 
846
  case INTERVAL_MONTH:
 
847
    period= (ltime->year*12 + sign * (long) interval.year*12 +
 
848
             ltime->month-1 + sign * (long) interval.month);
 
849
    if (period >= 120000L)
 
850
      goto invalid_date;
 
851
    ltime->year= (uint32_t) (period / 12);
 
852
    ltime->month= (uint32_t) (period % 12L)+1;
 
853
    /* Adjust day if the new month doesn't have enough days */
 
854
    if (ltime->day > days_in_month[ltime->month-1])
 
855
    {
 
856
      ltime->day = days_in_month[ltime->month-1];
 
857
      if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
 
858
        ltime->day++;                           // Leap-year
 
859
    }
 
860
    break;
 
861
  default:
 
862
    goto null_date;
 
863
  }
 
864
 
 
865
  return 0;                                     // Ok
 
866
 
 
867
invalid_date:
 
868
  push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
869
                      ER_DATETIME_FUNCTION_OVERFLOW,
 
870
                      ER(ER_DATETIME_FUNCTION_OVERFLOW),
 
871
                      "datetime");
 
872
null_date:
 
873
  return 1;
 
874
}
 
875
 
 
876
 
 
877
/*
 
878
  Calculate difference between two datetime values as seconds + microseconds.
 
879
 
 
880
  SYNOPSIS
 
881
    calc_time_diff()
 
882
      l_time1         - TIME/DATE/DATETIME value
 
883
      l_time2         - TIME/DATE/DATETIME value
 
884
      l_sign          - 1 absolute values are substracted,
 
885
                        -1 absolute values are added.
 
886
      seconds_out     - Out parameter where difference between
 
887
                        l_time1 and l_time2 in seconds is stored.
 
888
      microseconds_out- Out parameter where microsecond part of difference
 
889
                        between l_time1 and l_time2 is stored.
 
890
 
 
891
  NOTE
 
892
    This function calculates difference between l_time1 and l_time2 absolute
 
893
    values. So one should set l_sign and correct result if he want to take
 
894
    signs into account (i.e. for DRIZZLE_TIME values).
 
895
 
 
896
  RETURN VALUES
 
897
    Returns sign of difference.
 
898
    1 means negative result
 
899
    0 means positive result
 
900
 
 
901
*/
216
902
 
217
903
bool
218
 
calc_time_diff(type::Time *l_time1, type::Time *l_time2, int l_sign, int64_t *seconds_out,
 
904
calc_time_diff(DRIZZLE_TIME *l_time1, DRIZZLE_TIME *l_time2, int l_sign, int64_t *seconds_out,
219
905
               long *microseconds_out)
220
906
{
221
907
  long days;
227
913
    the second argument should be TIMESTAMP_TIME also.
228
914
    We should check it before calc_time_diff call.
229
915
  */
230
 
  if (l_time1->time_type == type::DRIZZLE_TIMESTAMP_TIME)  // Time value
 
916
  if (l_time1->time_type == DRIZZLE_TIMESTAMP_TIME)  // Time value
231
917
    days= (long)l_time1->day - l_sign * (long)l_time2->day;
232
918
  else
233
919
  {
234
920
    days= calc_daynr((uint32_t) l_time1->year,
235
 
                     (uint32_t) l_time1->month,
236
 
                     (uint32_t) l_time1->day);
237
 
    if (l_time2->time_type == type::DRIZZLE_TIMESTAMP_TIME)
 
921
                     (uint32_t) l_time1->month,
 
922
                     (uint32_t) l_time1->day);
 
923
    if (l_time2->time_type == DRIZZLE_TIMESTAMP_TIME)
238
924
      days-= l_sign * (long)l_time2->day;
239
925
    else
240
926
      days-= l_sign*calc_daynr((uint32_t) l_time2->year,
241
 
                               (uint32_t) l_time2->month,
242
 
                               (uint32_t) l_time2->day);
 
927
                               (uint32_t) l_time2->month,
 
928
                               (uint32_t) l_time2->day);
243
929
  }
244
930
 
245
931
  microseconds= ((int64_t)days*86400L +
246
932
                 (int64_t)(l_time1->hour*3600L +
247
 
                           l_time1->minute*60L +
248
 
                           l_time1->second) -
 
933
                            l_time1->minute*60L +
 
934
                            l_time1->second) -
249
935
                 l_sign*(int64_t)(l_time2->hour*3600L +
250
 
                                  l_time2->minute*60L +
251
 
                                  l_time2->second)) * 1000000L +
252
 
    (int64_t)l_time1->second_part -
253
 
    l_sign*(int64_t)l_time2->second_part;
 
936
                                   l_time2->minute*60L +
 
937
                                   l_time2->second)) * 1000000L +
 
938
                (int64_t)l_time1->second_part -
 
939
                l_sign*(int64_t)l_time2->second_part;
254
940
 
255
941
  neg= 0;
256
942
  if (microseconds < 0)
263
949
  return neg;
264
950
}
265
951
 
266
 
} /* namespace drizzled */
 
952
 
 
953
/*
 
954
  Compares 2 DRIZZLE_TIME structures
 
955
 
 
956
  SYNOPSIS
 
957
    my_time_compare()
 
958
 
 
959
      a - first time
 
960
      b - second time
 
961
 
 
962
  RETURN VALUE
 
963
   -1   - a < b
 
964
    0   - a == b
 
965
    1   - a > b
 
966
 
 
967
  NOTES
 
968
    TIME.second_part is not considered during comparison
 
969
*/
 
970
 
 
971
int
 
972
my_time_compare(DRIZZLE_TIME *a, DRIZZLE_TIME *b)
 
973
{
 
974
  uint64_t a_t= TIME_to_uint64_t_datetime(a);
 
975
  uint64_t b_t= TIME_to_uint64_t_datetime(b);
 
976
 
 
977
  if (a_t > b_t)
 
978
    return 1;
 
979
  else if (a_t < b_t)
 
980
    return -1;
 
981
 
 
982
  return 0;
 
983
}
 
984
 
 
985
#endif