~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/time.cc

  • Committer: Brian Aker
  • Date: 2009-03-20 18:52:05 UTC
  • mfrom: (950.1.1 mordred)
  • Revision ID: brian@tangent.org-20090320185205-g7o6kq17r25b6odf
Merge Monty

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>
32
28
 
33
29
/* Some functions to calculate dates */
34
30
 
 
31
#ifndef TESTTIME
 
32
 
 
33
/*
 
34
  Name description of interval names used in statements.
 
35
 
 
36
  'interval_type_to_name' is ordered and sorted on interval size and
 
37
  interval complexity.
 
38
  Order of elements in 'interval_type_to_name' should correspond to
 
39
  the order of elements in 'interval_type' enum
 
40
 
 
41
  See also interval_type, interval_names
 
42
*/
 
43
 
 
44
LEX_STRING interval_type_to_name[INTERVAL_LAST] = {
 
45
  { C_STRING_WITH_LEN("YEAR")},
 
46
  { C_STRING_WITH_LEN("QUARTER")},
 
47
  { C_STRING_WITH_LEN("MONTH")},
 
48
  { C_STRING_WITH_LEN("WEEK")},
 
49
  { C_STRING_WITH_LEN("DAY")},
 
50
  { C_STRING_WITH_LEN("HOUR")},
 
51
  { C_STRING_WITH_LEN("MINUTE")},
 
52
  { C_STRING_WITH_LEN("SECOND")},
 
53
  { C_STRING_WITH_LEN("MICROSECOND")},
 
54
  { C_STRING_WITH_LEN("YEAR_MONTH")},
 
55
  { C_STRING_WITH_LEN("DAY_HOUR")},
 
56
  { C_STRING_WITH_LEN("DAY_MINUTE")},
 
57
  { C_STRING_WITH_LEN("DAY_SECOND")},
 
58
  { C_STRING_WITH_LEN("HOUR_MINUTE")},
 
59
  { C_STRING_WITH_LEN("HOUR_SECOND")},
 
60
  { C_STRING_WITH_LEN("MINUTE_SECOND")},
 
61
  { C_STRING_WITH_LEN("DAY_MICROSECOND")},
 
62
  { C_STRING_WITH_LEN("HOUR_MICROSECOND")},
 
63
  { C_STRING_WITH_LEN("MINUTE_MICROSECOND")},
 
64
  { C_STRING_WITH_LEN("SECOND_MICROSECOND")}
 
65
};
 
66
 
 
67
        /* Calc weekday from daynr */
 
68
        /* Returns 0 for monday, 1 for tuesday .... */
35
69
 
36
70
int calc_weekday(long daynr,bool sunday_first_day_of_week)
37
71
{
38
72
  return ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7));
39
73
}
40
74
 
 
75
/*
 
76
  The bits in week_format has the following meaning:
 
77
   WEEK_MONDAY_FIRST (0)  If not set    Sunday is first day of week
 
78
                          If set        Monday is first day of week
 
79
   WEEK_YEAR (1)          If not set    Week is in range 0-53
 
80
 
 
81
        Week 0 is returned for the the last week of the previous year (for
 
82
        a date at start of january) In this case one can get 53 for the
 
83
        first week of next year.  This flag ensures that the week is
 
84
        relevant for the given year. Note that this flag is only
 
85
        releveant if WEEK_JANUARY is not set.
 
86
 
 
87
                          If set         Week is in range 1-53.
 
88
 
 
89
        In this case one may get week 53 for a date in January (when
 
90
        the week is that last week of previous year) and week 1 for a
 
91
        date in December.
 
92
 
 
93
  WEEK_FIRST_WEEKDAY (2)  If not set    Weeks are numbered according
 
94
                                        to ISO 8601:1988
 
95
                          If set        The week that contains the first
 
96
                                        'first-day-of-week' is week 1.
 
97
 
 
98
        ISO 8601:1988 means that if the week containing January 1 has
 
99
        four or more days in the new year, then it is week 1;
 
100
        Otherwise it is the last week of the previous year, and the
 
101
        next week is week 1.
 
102
*/
41
103
 
42
104
uint32_t calc_week(DRIZZLE_TIME *l_time, uint32_t week_behaviour, uint32_t *year)
43
105
{
48
110
  bool week_year= test(week_behaviour & WEEK_YEAR);
49
111
  bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
50
112
 
51
 
  uint32_t weekday= calc_weekday(first_daynr, !monday_first);
 
113
  uint32_t weekday=calc_weekday(first_daynr, !monday_first);
52
114
  *year=l_time->year;
53
115
 
54
116
  if (l_time->month == 1 && l_time->day <= 7-weekday)
79
141
  return days/7+1;
80
142
}
81
143
 
 
144
        /* Change a daynr to year, month and day */
 
145
        /* Daynr 0 is returned as date 00.00.00 */
82
146
 
83
 
void get_date_from_daynr(long daynr,
84
 
                         uint32_t *ret_year,
85
 
                         uint32_t *ret_month,
86
 
                                           uint32_t *ret_day)
 
147
void get_date_from_daynr(long daynr,uint32_t *ret_year,uint32_t *ret_month,
 
148
                         uint32_t *ret_day)
87
149
{
88
150
  uint32_t year,temp,leap_day,day_of_year,days_in_year;
89
151
  unsigned char *month_pos;
123
185
  return;
124
186
}
125
187
 
 
188
/*
 
189
  Convert a timestamp string to a DRIZZLE_TIME value and produce a warning
 
190
  if string was truncated during conversion.
 
191
 
 
192
  NOTE
 
193
    See description of str_to_datetime() for more information.
 
194
*/
126
195
 
127
196
enum enum_drizzle_timestamp_type
128
 
str_to_datetime_with_warn(const char *str, 
129
 
                          uint32_t length, 
130
 
                          DRIZZLE_TIME *l_time,
 
197
str_to_datetime_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time,
131
198
                          uint32_t flags)
132
199
{
133
200
  int was_cut;
 
201
  Session *session= current_session;
134
202
  enum enum_drizzle_timestamp_type ts_type;
135
 
  Session *session= current_session;
136
203
 
137
204
  ts_type= str_to_datetime(str, length, l_time,
138
205
                           (flags | (session->variables.sql_mode &
140
207
                                      MODE_NO_ZERO_DATE))),
141
208
                           &was_cut);
142
209
  if (was_cut || ts_type <= DRIZZLE_TIMESTAMP_ERROR)
143
 
    make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
210
    make_truncated_value_warning(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
144
211
                                 str, length, ts_type,  NULL);
145
212
  return ts_type;
146
213
}
147
214
 
 
215
/*
 
216
  Convert a time string to a DRIZZLE_TIME struct and produce a warning
 
217
  if string was cut during conversion.
148
218
 
 
219
  NOTE
 
220
    See str_to_time() for more info.
 
221
*/
149
222
bool
150
223
str_to_time_with_warn(const char *str, uint32_t length, DRIZZLE_TIME *l_time)
151
224
{
158
231
}
159
232
 
160
233
 
 
234
/*
 
235
  Convert a system time structure to TIME
 
236
*/
 
237
 
161
238
void localtime_to_TIME(DRIZZLE_TIME *to, struct tm *from)
162
239
{
163
240
  to->neg=0;
170
247
  to->second=   (int) from->tm_sec;
171
248
}
172
249
 
 
250
void calc_time_from_sec(DRIZZLE_TIME *to, long seconds, long microseconds)
 
251
{
 
252
  long t_seconds;
 
253
  // to->neg is not cleared, it may already be set to a useful value
 
254
  to->time_type= DRIZZLE_TIMESTAMP_TIME;
 
255
  to->year= 0;
 
256
  to->month= 0;
 
257
  to->day= 0;
 
258
  to->hour= seconds/3600L;
 
259
  t_seconds= seconds%3600L;
 
260
  to->minute= t_seconds/60L;
 
261
  to->second= t_seconds%60L;
 
262
  to->second_part= microseconds;
 
263
}
 
264
 
 
265
void make_time(const DRIZZLE_TIME *l_time, String *str)
 
266
{
 
267
  str->alloc(MAX_DATE_STRING_REP_LENGTH);
 
268
  uint32_t length= (uint32_t) my_time_to_str(l_time, str->c_ptr());
 
269
  str->length(length);
 
270
  str->set_charset(&my_charset_bin);
 
271
}
 
272
 
 
273
 
173
274
void make_date(const DRIZZLE_TIME *l_time, String *str)
174
275
{
175
276
  str->alloc(MAX_DATE_STRING_REP_LENGTH);
188
289
}
189
290
 
190
291
 
191
 
void make_truncated_value_warning(Session *session, 
192
 
                                  DRIZZLE_ERROR::enum_warning_level level,
 
292
void make_truncated_value_warning(Session *session, DRIZZLE_ERROR::enum_warning_level level,
193
293
                                  const char *str_val,
194
 
                                                          uint32_t str_length,
 
294
                                  uint32_t str_length,
195
295
                                  enum enum_drizzle_timestamp_type time_type,
196
296
                                  const char *field_name)
197
297
{
216
316
      break;
217
317
  }
218
318
  if (field_name)
219
 
  {
220
319
    cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
221
320
                       ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
222
321
                       type_str, str.c_ptr(), field_name,
223
322
                       (uint32_t) session->row_count);
224
 
  }
225
323
  else
226
324
  {
227
325
    if (time_type > DRIZZLE_TIMESTAMP_ERROR)
236
334
               ER_TRUNCATED_WRONG_VALUE, warn_buff);
237
335
}
238
336
 
 
337
bool date_add_interval(DRIZZLE_TIME *ltime, interval_type int_type, INTERVAL interval)
 
338
{
 
339
  long period, sign;
 
340
 
 
341
  ltime->neg= 0;
 
342
 
 
343
  sign= (interval.neg ? -1 : 1);
 
344
 
 
345
  switch (int_type) {
 
346
  case INTERVAL_SECOND:
 
347
  case INTERVAL_SECOND_MICROSECOND:
 
348
  case INTERVAL_MICROSECOND:
 
349
  case INTERVAL_MINUTE:
 
350
  case INTERVAL_HOUR:
 
351
  case INTERVAL_MINUTE_MICROSECOND:
 
352
  case INTERVAL_MINUTE_SECOND:
 
353
  case INTERVAL_HOUR_MICROSECOND:
 
354
  case INTERVAL_HOUR_SECOND:
 
355
  case INTERVAL_HOUR_MINUTE:
 
356
  case INTERVAL_DAY_MICROSECOND:
 
357
  case INTERVAL_DAY_SECOND:
 
358
  case INTERVAL_DAY_MINUTE:
 
359
  case INTERVAL_DAY_HOUR:
 
360
  {
 
361
    int64_t sec, days, daynr, microseconds, extra_sec;
 
362
    ltime->time_type= DRIZZLE_TIMESTAMP_DATETIME; // Return full date
 
363
    microseconds= ltime->second_part + sign*interval.second_part;
 
364
    extra_sec= microseconds/1000000L;
 
365
    microseconds= microseconds%1000000L;
 
366
 
 
367
    sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+
 
368
         ltime->second +
 
369
         sign* (int64_t) (interval.day*3600*24L +
 
370
                           interval.hour*3600L+interval.minute*60L+
 
371
                           interval.second))+ extra_sec;
 
372
    if (microseconds < 0)
 
373
    {
 
374
      microseconds+= 1000000L;
 
375
      sec--;
 
376
    }
 
377
    days= sec/(3600*24L);
 
378
    sec-= days*3600*24L;
 
379
    if (sec < 0)
 
380
    {
 
381
      days--;
 
382
      sec+= 3600*24L;
 
383
    }
 
384
    ltime->second_part= (uint32_t) microseconds;
 
385
    ltime->second= (uint32_t) (sec % 60);
 
386
    ltime->minute= (uint32_t) (sec/60 % 60);
 
387
    ltime->hour=   (uint32_t) (sec/3600);
 
388
    daynr= calc_daynr(ltime->year,ltime->month,1) + days;
 
389
    /* Day number from year 0 to 9999-12-31 */
 
390
    if ((uint64_t) daynr > MAX_DAY_NUMBER)
 
391
      goto invalid_date;
 
392
    get_date_from_daynr((long) daynr, &ltime->year, &ltime->month,
 
393
                        &ltime->day);
 
394
    break;
 
395
  }
 
396
  case INTERVAL_DAY:
 
397
  case INTERVAL_WEEK:
 
398
    period= (calc_daynr(ltime->year,ltime->month,ltime->day) +
 
399
             sign * (long) interval.day);
 
400
    /* Daynumber from year 0 to 9999-12-31 */
 
401
    if (period > MAX_DAY_NUMBER)
 
402
      goto invalid_date;
 
403
    get_date_from_daynr((long) period,&ltime->year,&ltime->month,&ltime->day);
 
404
    break;
 
405
  case INTERVAL_YEAR:
 
406
    ltime->year+= sign * (long) interval.year;
 
407
    if (ltime->year >= 10000L)
 
408
      goto invalid_date;
 
409
    if (ltime->month == 2 && ltime->day == 29 &&
 
410
        calc_days_in_year(ltime->year) != 366)
 
411
      ltime->day=28;                            // Was leap-year
 
412
    break;
 
413
  case INTERVAL_YEAR_MONTH:
 
414
  case INTERVAL_QUARTER:
 
415
  case INTERVAL_MONTH:
 
416
    period= (ltime->year*12 + sign * (long) interval.year*12 +
 
417
             ltime->month-1 + sign * (long) interval.month);
 
418
    if (period >= 120000L)
 
419
      goto invalid_date;
 
420
    ltime->year= (uint32_t) (period / 12);
 
421
    ltime->month= (uint32_t) (period % 12L)+1;
 
422
    /* Adjust day if the new month doesn't have enough days */
 
423
    if (ltime->day > days_in_month[ltime->month-1])
 
424
    {
 
425
      ltime->day = days_in_month[ltime->month-1];
 
426
      if (ltime->month == 2 && calc_days_in_year(ltime->year) == 366)
 
427
        ltime->day++;                           // Leap-year
 
428
    }
 
429
    break;
 
430
  default:
 
431
    goto null_date;
 
432
  }
 
433
 
 
434
  return 0;                                     // Ok
 
435
 
 
436
invalid_date:
 
437
  push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
438
                      ER_DATETIME_FUNCTION_OVERFLOW,
 
439
                      ER(ER_DATETIME_FUNCTION_OVERFLOW),
 
440
                      "datetime");
 
441
null_date:
 
442
  return 1;
 
443
}
 
444
 
 
445
 
 
446
/*
 
447
  Calculate difference between two datetime values as seconds + microseconds.
 
448
 
 
449
  SYNOPSIS
 
450
    calc_time_diff()
 
451
      l_time1         - TIME/DATE/DATETIME value
 
452
      l_time2         - TIME/DATE/DATETIME value
 
453
      l_sign          - 1 absolute values are substracted,
 
454
                        -1 absolute values are added.
 
455
      seconds_out     - Out parameter where difference between
 
456
                        l_time1 and l_time2 in seconds is stored.
 
457
      microseconds_out- Out parameter where microsecond part of difference
 
458
                        between l_time1 and l_time2 is stored.
 
459
 
 
460
  NOTE
 
461
    This function calculates difference between l_time1 and l_time2 absolute
 
462
    values. So one should set l_sign and correct result if he want to take
 
463
    signs into account (i.e. for DRIZZLE_TIME values).
 
464
 
 
465
  RETURN VALUES
 
466
    Returns sign of difference.
 
467
    1 means negative result
 
468
    0 means positive result
 
469
 
 
470
*/
239
471
 
240
472
bool
241
473
calc_time_diff(DRIZZLE_TIME *l_time1, DRIZZLE_TIME *l_time2, int l_sign, int64_t *seconds_out,
286
518
  return neg;
287
519
}
288
520
 
289
 
} /* namespace drizzled */
 
521
 
 
522
/*
 
523
  Compares 2 DRIZZLE_TIME structures
 
524
 
 
525
  SYNOPSIS
 
526
    my_time_compare()
 
527
 
 
528
      a - first time
 
529
      b - second time
 
530
 
 
531
  RETURN VALUE
 
532
   -1   - a < b
 
533
    0   - a == b
 
534
    1   - a > b
 
535
 
 
536
  NOTES
 
537
    TIME.second_part is not considered during comparison
 
538
*/
 
539
 
 
540
int
 
541
my_time_compare(DRIZZLE_TIME *a, DRIZZLE_TIME *b)
 
542
{
 
543
  uint64_t a_t= TIME_to_uint64_t_datetime(a);
 
544
  uint64_t b_t= TIME_to_uint64_t_datetime(b);
 
545
 
 
546
  if (a_t > b_t)
 
547
    return 1;
 
548
  else if (a_t < b_t)
 
549
    return -1;
 
550
 
 
551
  return 0;
 
552
}
 
553
 
 
554
#endif