~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/time_functions.cc

  • Committer: Brian Aker
  • Date: 2010-12-08 22:35:56 UTC
  • mfrom: (1819.9.158 update-innobase)
  • Revision ID: brian@tangent.org-20101208223556-37mi4omqg7lkjzf3
Merge in Stewart's changes, 1.3 changes.

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 Sun Microsystems
 
4
 *  Copyright (C) 2008-2009 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 <drizzled/server_includes.h>
24
 
#include <drizzled/error.h>
25
 
#include <drizzled/util/test.h>
26
 
#include <drizzled/tztime.h>
27
 
#include <drizzled/item/timefunc.h>
28
 
#include <drizzled/session.h>
 
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
{
29
32
 
30
33
/* Some functions to calculate dates */
31
34
 
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 .... */
70
35
 
71
36
int calc_weekday(long daynr,bool sunday_first_day_of_week)
72
37
{
73
38
  return ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
74
39
}
75
40
 
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
41
 
105
42
uint32_t calc_week(DRIZZLE_TIME *l_time, uint32_t week_behaviour, uint32_t *year)
106
43
{
111
48
  bool week_year= test(week_behaviour & WEEK_YEAR);
112
49
  bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
113
50
 
114
 
  uint32_t weekday=calc_weekday(first_daynr, !monday_first);
 
51
  uint32_t weekday= calc_weekday(first_daynr, !monday_first);
115
52
  *year=l_time->year;
116
53
 
117
54
  if (l_time->month == 1 && l_time->day <= 7-weekday)
142
79
  return days/7+1;
143
80
}
144
81
 
145
 
        /* Change a daynr to year, month and day */
146
 
        /* Daynr 0 is returned as date 00.00.00 */
147
82
 
148
 
void get_date_from_daynr(long daynr,uint32_t *ret_year,uint32_t *ret_month,
149
 
                         uint32_t *ret_day)
 
83
void get_date_from_daynr(long daynr,
 
84
                         uint32_t *ret_year,
 
85
                         uint32_t *ret_month,
 
86
                                           uint32_t *ret_day)
150
87
{
151
88
  uint32_t year,temp,leap_day,day_of_year,days_in_year;
152
89
  unsigned char *month_pos;
157
94
  }
158
95
  else
159
96
  {
160
 
    year= (uint) (daynr*100 / 36525L);
 
97
    year= (uint32_t) (daynr*100 / 36525L);
161
98
    temp=(((year-1)/100+1)*3)/4;
162
 
    day_of_year=(uint) (daynr - (long) year * 365L) - (year-1)/4 +temp;
 
99
    day_of_year=(uint32_t) (daynr - (long) year * 365L) - (year-1)/4 +temp;
163
100
    while (day_of_year > (days_in_year= calc_days_in_year(year)))
164
101
    {
165
102
      day_of_year-=days_in_year;
177
114
    }
178
115
    *ret_month=1;
179
116
    for (month_pos= days_in_month ;
180
 
         day_of_year > (uint) *month_pos ;
 
117
         day_of_year > (uint32_t) *month_pos ;
181
118
         day_of_year-= *(month_pos++), (*ret_month)++)
182
119
      ;
183
120
    *ret_year=year;
186
123
  return;
187
124
}
188
125
 
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
126
 
226
127
enum enum_drizzle_timestamp_type
227
 
str_to_datetime_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
 
128
str_to_datetime_with_warn(const char *str, 
 
129
                          uint32_t length, 
 
130
                          DRIZZLE_TIME *l_time,
228
131
                          uint32_t flags)
229
132
{
230
133
  int was_cut;
 
134
  enum enum_drizzle_timestamp_type ts_type;
231
135
  Session *session= current_session;
232
 
  enum enum_drizzle_timestamp_type ts_type;
233
 
  
 
136
 
234
137
  ts_type= str_to_datetime(str, length, l_time,
235
138
                           (flags | (session->variables.sql_mode &
236
139
                                     (MODE_INVALID_DATES |
237
140
                                      MODE_NO_ZERO_DATE))),
238
141
                           &was_cut);
239
142
  if (was_cut || ts_type <= DRIZZLE_TIMESTAMP_ERROR)
240
 
    make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
143
    make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
241
144
                                 str, length, ts_type,  NULL);
242
145
  return ts_type;
243
146
}
244
147
 
245
148
 
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
 
my_time_t TIME_to_timestamp(Session *session, const DRIZZLE_TIME *t,
264
 
                            bool *in_dst_time_gap)
265
 
{
266
 
  my_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
 
*/
288
149
bool
289
150
str_to_time_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time)
290
151
{
297
158
}
298
159
 
299
160
 
300
 
/*
301
 
  Convert a system time structure to TIME
302
 
*/
303
 
 
304
161
void localtime_to_TIME(DRIZZLE_TIME *to, struct tm *from)
305
162
{
306
163
  to->neg=0;
313
170
  to->second=   (int) from->tm_sec;
314
171
}
315
172
 
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 *) my_malloc(length, MYF(MY_WME));
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 *format __attribute__((unused)),
697
 
               const DRIZZLE_TIME *l_time, String *str)
698
 
{
699
 
  uint32_t length= (uint) 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 *format __attribute__((unused)),
706
 
               const DRIZZLE_TIME *l_time, String *str)
707
 
{
708
 
  uint32_t length= (uint) 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 *format __attribute__((unused)),
715
 
                   const DRIZZLE_TIME *l_time, String *str)
716
 
{
717
 
  uint32_t length= (uint) 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,
 
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,
724
193
                                  const char *str_val,
725
 
                                  uint32_t str_length,
 
194
                                                          uint32_t str_length,
726
195
                                  enum enum_drizzle_timestamp_type time_type,
727
196
                                  const char *field_name)
728
197
{
735
204
  str[str_length]= 0;               // Ensure we have end 0 for snprintf
736
205
 
737
206
  switch (time_type) {
738
 
    case DRIZZLE_TIMESTAMP_DATE: 
 
207
    case DRIZZLE_TIMESTAMP_DATE:
739
208
      type_str= "date";
740
209
      break;
741
210
    case DRIZZLE_TIMESTAMP_TIME:
747
216
      break;
748
217
  }
749
218
  if (field_name)
 
219
  {
750
220
    cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
751
221
                       ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
752
222
                       type_str, str.c_ptr(), field_name,
753
223
                       (uint32_t) session->row_count);
 
224
  }
754
225
  else
755
226
  {
756
227
    if (time_type > DRIZZLE_TIMESTAMP_ERROR)
765
236
               ER_TRUNCATED_WRONG_VALUE, warn_buff);
766
237
}
767
238
 
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= (uint) microseconds;
816
 
    ltime->second= (uint) (sec % 60);
817
 
    ltime->minute= (uint) (sec/60 % 60);
818
 
    ltime->hour=   (uint) (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= (uint) (period / 12);
852
 
    ltime->month= (uint) (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
 
*/
902
239
 
903
240
bool
904
241
calc_time_diff(DRIZZLE_TIME *l_time1, DRIZZLE_TIME *l_time2, int l_sign, int64_t *seconds_out,
917
254
    days= (long)l_time1->day - l_sign * (long)l_time2->day;
918
255
  else
919
256
  {
920
 
    days= calc_daynr((uint) l_time1->year,
921
 
                     (uint) l_time1->month,
922
 
                     (uint) l_time1->day);
 
257
    days= calc_daynr((uint32_t) l_time1->year,
 
258
                     (uint32_t) l_time1->month,
 
259
                     (uint32_t) l_time1->day);
923
260
    if (l_time2->time_type == DRIZZLE_TIMESTAMP_TIME)
924
261
      days-= l_sign * (long)l_time2->day;
925
262
    else
926
 
      days-= l_sign*calc_daynr((uint) l_time2->year,
927
 
                               (uint) l_time2->month,
928
 
                               (uint) l_time2->day);
 
263
      days-= l_sign*calc_daynr((uint32_t) l_time2->year,
 
264
                               (uint32_t) l_time2->month,
 
265
                               (uint32_t) l_time2->day);
929
266
  }
930
267
 
931
268
  microseconds= ((int64_t)days*86400L +
949
286
  return neg;
950
287
}
951
288
 
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
 
289
} /* namespace drizzled */