~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/time.cc

  • Committer: Jay Pipes
  • Date: 2009-02-21 16:00:06 UTC
  • mto: (907.1.1 trunk-with-temporal)
  • mto: This revision was merged to the branch mainline in revision 908.
  • Revision ID: jpipes@serialcoder-20090221160006-vnk3wt4qbcz62eru
Removes the TIME column type and related time functions.

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
 
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
 
 
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
*/
41
104
 
42
105
uint32_t calc_week(DRIZZLE_TIME *l_time, uint32_t week_behaviour, uint32_t *year)
43
106
{
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;
123
186
  return;
124
187
}
125
188
 
 
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
*/
126
225
 
127
226
enum enum_drizzle_timestamp_type
128
 
str_to_datetime_with_warn(const char *str, 
129
 
                          uint32_t length, 
130
 
                          DRIZZLE_TIME *l_time,
 
227
str_to_datetime_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
131
228
                          uint32_t flags)
132
229
{
133
230
  int was_cut;
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
289
str_to_time_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time)
151
290
{
158
297
}
159
298
 
160
299
 
 
300
/*
 
301
  Convert a system time structure to TIME
 
302
*/
 
303
 
161
304
void localtime_to_TIME(DRIZZLE_TIME *to, struct tm *from)
162
305
{
163
306
  to->neg=0;
170
313
  to->second=   (int) from->tm_sec;
171
314
}
172
315
 
173
 
void make_date(const DRIZZLE_TIME *l_time, String *str)
174
 
{
175
 
  str->alloc(MAX_DATE_STRING_REP_LENGTH);
176
 
  uint32_t length= (uint32_t) my_date_to_str(l_time, str->c_ptr());
177
 
  str->length(length);
178
 
  str->set_charset(&my_charset_bin);
179
 
}
180
 
 
181
 
 
182
 
void make_datetime(const DRIZZLE_TIME *l_time, String *str)
183
 
{
184
 
  str->alloc(MAX_DATE_STRING_REP_LENGTH);
185
 
  uint32_t length= (uint32_t) my_datetime_to_str(l_time, str->c_ptr());
186
 
  str->length(length);
187
 
  str->set_charset(&my_charset_bin);
188
 
}
189
 
 
190
 
 
191
 
void make_truncated_value_warning(Session *session, 
192
 
                                  DRIZZLE_ERROR::enum_warning_level level,
 
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,
193
724
                                  const char *str_val,
194
 
                                                          uint32_t str_length,
 
725
                                  uint32_t str_length,
195
726
                                  enum enum_drizzle_timestamp_type time_type,
196
727
                                  const char *field_name)
197
728
{
234
765
               ER_TRUNCATED_WRONG_VALUE, warn_buff);
235
766
}
236
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
*/
237
902
 
238
903
bool
239
904
calc_time_diff(DRIZZLE_TIME *l_time1, DRIZZLE_TIME *l_time2, int l_sign, int64_t *seconds_out,
284
949
  return neg;
285
950
}
286
951
 
287
 
} /* 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