~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/tztime.cc

  • Committer: Brian Aker
  • Date: 2009-01-07 21:26:58 UTC
  • Revision ID: brian@tangent.org-20090107212658-2fh0s2uwh10w68y2
Committing fix lock_multi

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 */
19
19
 
20
20
 
21
 
#include "config.h"
22
 
#include <cstdio>
23
 
#include "drizzled/tzfile.h"
24
 
#include "drizzled/tztime.h"
25
 
#include "drizzled/gettext.h"
26
 
#include "drizzled/session.h"
27
 
#include "drizzled/time_functions.h"
28
 
 
29
 
namespace drizzled
30
 
{
31
 
 
32
 
/**
33
 
 * String with names of SYSTEM time zone.
34
 
 */
 
21
#include <drizzled/server_includes.h>
 
22
#include <drizzled/tzfile.h>
 
23
#include <drizzled/tztime.h>
 
24
#include <drizzled/gettext.h>
 
25
#include <drizzled/session.h>
 
26
 
 
27
/* Structure describing local time type (e.g. Moscow summer time (MSD)) */
 
28
typedef struct ttinfo
 
29
{
 
30
  long tt_gmtoff; // Offset from UTC in seconds
 
31
  uint32_t tt_isdst;   // Is daylight saving time or not. Used to set tm_isdst
 
32
  uint32_t tt_abbrind; // Index of start of abbreviation for this time type.
 
33
  /*
 
34
    We don't use tt_ttisstd and tt_ttisgmt members of original elsie-code
 
35
    struct since we don't support POSIX-style TZ descriptions in variables.
 
36
  */
 
37
} TRAN_TYPE_INFO;
 
38
 
 
39
/* Structure describing leap-second corrections. */
 
40
typedef struct lsinfo
 
41
{
 
42
  time_t ls_trans; // Transition time
 
43
  long      ls_corr;  // Correction to apply
 
44
} LS_INFO;
 
45
 
 
46
/*
 
47
  Structure with information describing ranges of time_t shifted to local
 
48
  time (time_t + offset). Used for local DRIZZLE_TIME -> time_t conversion.
 
49
  See comments for TIME_to_gmt_sec() for more info.
 
50
*/
 
51
typedef struct revtinfo
 
52
{
 
53
  long rt_offset; // Offset of local time from UTC in seconds
 
54
  uint32_t rt_type;    // Type of period 0 - Normal period. 1 - Spring time-gap
 
55
} REVT_INFO;
 
56
 
 
57
 
 
58
/*
 
59
  Structure which fully describes time zone which is
 
60
  described in our db or in zoneinfo files.
 
61
*/
 
62
typedef struct st_time_zone_info
 
63
{
 
64
  uint32_t leapcnt;  // Number of leap-second corrections
 
65
  uint32_t timecnt;  // Number of transitions between time types
 
66
  uint32_t typecnt;  // Number of local time types
 
67
  uint32_t charcnt;  // Number of characters used for abbreviations
 
68
  uint32_t revcnt;   // Number of transition descr. for TIME->time_t conversion
 
69
  /* The following are dynamical arrays are allocated in MEM_ROOT */
 
70
  time_t *ats;       // Times of transitions between time types
 
71
  unsigned char *types; // Local time types for transitions
 
72
  TRAN_TYPE_INFO *ttis; // Local time types descriptions
 
73
  /* Storage for local time types abbreviations. They are stored as ASCIIZ */
 
74
  char *chars;
 
75
  /*
 
76
    Leap seconds corrections descriptions, this array is shared by
 
77
    all time zones who use leap seconds.
 
78
  */
 
79
  LS_INFO *lsis;
 
80
  /*
 
81
    Starting points and descriptions of shifted time_t (time_t + offset)
 
82
    ranges on which shifted time_t -> time_t mapping is linear or undefined.
 
83
    Used for tm -> time_t conversion.
 
84
  */
 
85
  time_t *revts;
 
86
  REVT_INFO *revtis;
 
87
  /*
 
88
    Time type which is used for times smaller than first transition or if
 
89
    there are no transitions at all.
 
90
  */
 
91
  TRAN_TYPE_INFO *fallback_tti;
 
92
 
 
93
} TIME_ZONE_INFO;
 
94
 
 
95
 
 
96
#if !defined(TZINFO2SQL)
 
97
 
 
98
static const uint32_t mon_lengths[2][MONS_PER_YEAR]=
 
99
{
 
100
  { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
 
101
  { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
 
102
};
 
103
 
 
104
static const uint32_t mon_starts[2][MONS_PER_YEAR]=
 
105
{
 
106
  { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
 
107
  { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
 
108
};
 
109
 
 
110
static const uint32_t year_lengths[2]=
 
111
{
 
112
  DAYS_PER_NYEAR, DAYS_PER_LYEAR
 
113
};
 
114
 
 
115
#define LEAPS_THRU_END_OF(y)  ((y) / 4 - (y) / 100 + (y) / 400)
 
116
 
 
117
 
 
118
/*
 
119
  Converts time from time_t representation (seconds in UTC since Epoch)
 
120
  to broken down representation using given local time zone offset.
 
121
 
 
122
  SYNOPSIS
 
123
    sec_to_TIME()
 
124
      tmp    - pointer to structure for broken down representation
 
125
      t      - time_t value to be converted
 
126
      offset - local time zone offset
 
127
 
 
128
  DESCRIPTION
 
129
    Convert time_t with offset to DRIZZLE_TIME struct. Differs from timesub
 
130
    (from elsie code) because doesn't contain any leap correction and
 
131
    TM_GMTOFF and is_dst setting and contains some MySQL specific
 
132
    initialization. Funny but with removing of these we almost have
 
133
    glibc's offtime function.
 
134
*/
 
135
static void
 
136
sec_to_TIME(DRIZZLE_TIME * tmp, time_t t, long offset)
 
137
{
 
138
  long days;
 
139
  long rem;
 
140
  int y;
 
141
  int yleap;
 
142
  const uint32_t *ip;
 
143
 
 
144
  days= (long) (t / SECS_PER_DAY);
 
145
  rem=  (long) (t % SECS_PER_DAY);
 
146
 
 
147
  /*
 
148
    We do this as separate step after dividing t, because this
 
149
    allows us handle times near time_t bounds without overflows.
 
150
  */
 
151
  rem+= offset;
 
152
  while (rem < 0)
 
153
  {
 
154
    rem+= SECS_PER_DAY;
 
155
    days--;
 
156
  }
 
157
  while (rem >= SECS_PER_DAY)
 
158
  {
 
159
    rem -= SECS_PER_DAY;
 
160
    days++;
 
161
  }
 
162
  tmp->hour= (uint)(rem / SECS_PER_HOUR);
 
163
  rem= rem % SECS_PER_HOUR;
 
164
  tmp->minute= (uint)(rem / SECS_PER_MIN);
 
165
  /*
 
166
    A positive leap second requires a special
 
167
    representation.  This uses "... ??:59:60" et seq.
 
168
  */
 
169
  tmp->second= (uint)(rem % SECS_PER_MIN);
 
170
 
 
171
  y= EPOCH_YEAR;
 
172
  while (days < 0 || days >= (long)year_lengths[yleap= isleap(y)])
 
173
  {
 
174
    int newy;
 
175
 
 
176
    newy= y + days / DAYS_PER_NYEAR;
 
177
    if (days < 0)
 
178
      newy--;
 
179
    days-= (newy - y) * DAYS_PER_NYEAR +
 
180
           LEAPS_THRU_END_OF(newy - 1) -
 
181
           LEAPS_THRU_END_OF(y - 1);
 
182
    y= newy;
 
183
  }
 
184
  tmp->year= y;
 
185
 
 
186
  ip= mon_lengths[yleap];
 
187
  for (tmp->month= 0; days >= (long) ip[tmp->month]; tmp->month++)
 
188
    days= days - (long) ip[tmp->month];
 
189
  tmp->month++;
 
190
  tmp->day= (uint)(days + 1);
 
191
 
 
192
  /* filling MySQL specific DRIZZLE_TIME members */
 
193
  tmp->neg= 0; tmp->second_part= 0;
 
194
  tmp->time_type= DRIZZLE_TIMESTAMP_DATETIME;
 
195
}
 
196
 
 
197
 
 
198
/*
 
199
  Find time range wich contains given time_t value
 
200
 
 
201
  SYNOPSIS
 
202
    find_time_range()
 
203
      t                - time_t value for which we looking for range
 
204
      range_boundaries - sorted array of range starts.
 
205
      higher_bound     - number of ranges
 
206
 
 
207
  DESCRIPTION
 
208
    Performs binary search for range which contains given time_t value.
 
209
    It has sense if number of ranges is greater than zero and time_t value
 
210
    is greater or equal than beginning of first range. It also assumes that
 
211
    t belongs to some range specified.
 
212
 
 
213
    With this localtime_r on real data may takes less time than with linear
 
214
    search (I've seen 30% speed up).
 
215
 
 
216
  RETURN VALUE
 
217
    Index of range to which t belongs
 
218
*/
 
219
static uint
 
220
find_time_range(time_t t, const time_t *range_boundaries,
 
221
                uint32_t higher_bound)
 
222
{
 
223
  uint32_t i, lower_bound= 0;
 
224
 
 
225
  /*
 
226
    Function will work without this assertion but result would be meaningless.
 
227
  */
 
228
  assert(higher_bound > 0 && t >= range_boundaries[0]);
 
229
 
 
230
  /*
 
231
    Do binary search for minimal interval which contain t. We preserve:
 
232
    range_boundaries[lower_bound] <= t < range_boundaries[higher_bound]
 
233
    invariant and decrease this higher_bound - lower_bound gap twice
 
234
    times on each step.
 
235
  */
 
236
 
 
237
  while (higher_bound - lower_bound > 1)
 
238
  {
 
239
    i= (lower_bound + higher_bound) >> 1;
 
240
    if (range_boundaries[i] <= t)
 
241
      lower_bound= i;
 
242
    else
 
243
      higher_bound= i;
 
244
  }
 
245
  return lower_bound;
 
246
}
 
247
 
 
248
/*
 
249
  Find local time transition for given time_t.
 
250
 
 
251
  SYNOPSIS
 
252
    find_transition_type()
 
253
      t   - time_t value to be converted
 
254
      sp  - pointer to struct with time zone description
 
255
 
 
256
  RETURN VALUE
 
257
    Pointer to structure in time zone description describing
 
258
    local time type for given time_t.
 
259
*/
 
260
static
 
261
const TRAN_TYPE_INFO *
 
262
find_transition_type(time_t t, const TIME_ZONE_INFO *sp)
 
263
{
 
264
  if (unlikely(sp->timecnt == 0 || t < sp->ats[0]))
 
265
  {
 
266
    /*
 
267
      If we have not any transitions or t is before first transition let
 
268
      us use fallback time type.
 
269
    */
 
270
    return sp->fallback_tti;
 
271
  }
 
272
 
 
273
  /*
 
274
    Do binary search for minimal interval between transitions which
 
275
    contain t. With this localtime_r on real data may takes less
 
276
    time than with linear search (I've seen 30% speed up).
 
277
  */
 
278
  return &(sp->ttis[sp->types[find_time_range(t, sp->ats, sp->timecnt)]]);
 
279
}
 
280
 
 
281
 
 
282
/*
 
283
  Converts time in time_t representation (seconds in UTC since Epoch) to
 
284
  broken down DRIZZLE_TIME representation in local time zone.
 
285
 
 
286
  SYNOPSIS
 
287
    gmt_sec_to_TIME()
 
288
      tmp          - pointer to structure for broken down represenatation
 
289
      sec_in_utc   - time_t value to be converted
 
290
      sp           - pointer to struct with time zone description
 
291
 
 
292
  TODO
 
293
    We can improve this function by creating joined array of transitions and
 
294
    leap corrections. This will require adding extra field to TRAN_TYPE_INFO
 
295
    for storing number of "extra" seconds to minute occured due to correction
 
296
    (60th and 61st second, look how we calculate them as "hit" in this
 
297
    function).
 
298
    Under realistic assumptions about frequency of transitions the same array
 
299
    can be used for DRIZZLE_TIME -> time_t conversion. For this we need to
 
300
    implement tweaked binary search which will take into account that some
 
301
    DRIZZLE_TIME has two matching time_t ranges and some of them have none.
 
302
*/
 
303
static void
 
304
gmt_sec_to_TIME(DRIZZLE_TIME *tmp, time_t sec_in_utc, const TIME_ZONE_INFO *sp)
 
305
{
 
306
  const TRAN_TYPE_INFO *ttisp;
 
307
  const LS_INFO *lp;
 
308
  long  corr= 0;
 
309
  int   hit= 0;
 
310
  int   i;
 
311
 
 
312
  /*
 
313
    Find proper transition (and its local time type) for our sec_in_utc value.
 
314
    Funny but again by separating this step in function we receive code
 
315
    which very close to glibc's code. No wonder since they obviously use
 
316
    the same base and all steps are sensible.
 
317
  */
 
318
  ttisp= find_transition_type(sec_in_utc, sp);
 
319
 
 
320
  /*
 
321
    Let us find leap correction for our sec_in_utc value and number of extra
 
322
    secs to add to this minute.
 
323
    This loop is rarely used because most users will use time zones without
 
324
    leap seconds, and even in case when we have such time zone there won't
 
325
    be many iterations (we have about 22 corrections at this moment (2004)).
 
326
  */
 
327
  for ( i= sp->leapcnt; i-- > 0; )
 
328
  {
 
329
    lp= &sp->lsis[i];
 
330
    if (sec_in_utc >= lp->ls_trans)
 
331
    {
 
332
      if (sec_in_utc == lp->ls_trans)
 
333
      {
 
334
        hit= ((i == 0 && lp->ls_corr > 0) ||
 
335
              lp->ls_corr > sp->lsis[i - 1].ls_corr);
 
336
        if (hit)
 
337
        {
 
338
          while (i > 0 &&
 
339
                 sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 &&
 
340
                 sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1)
 
341
          {
 
342
            hit++;
 
343
            i--;
 
344
          }
 
345
        }
 
346
      }
 
347
      corr= lp->ls_corr;
 
348
      break;
 
349
    }
 
350
  }
 
351
 
 
352
  sec_to_TIME(tmp, sec_in_utc, ttisp->tt_gmtoff - corr);
 
353
 
 
354
  tmp->second+= hit;
 
355
}
 
356
 
 
357
 
 
358
/*
 
359
  Converts local time in broken down representation to local
 
360
  time zone analog of time_t represenation.
 
361
 
 
362
  SYNOPSIS
 
363
    sec_since_epoch()
 
364
      year, mon, mday, hour, min, sec - broken down representation.
 
365
 
 
366
  DESCRIPTION
 
367
    Converts time in broken down representation to time_t representation
 
368
    ignoring time zone. Note that we cannot convert back some valid _local_
 
369
    times near ends of time_t range because of time_t overflow. But we
 
370
    ignore this fact now since MySQL will never pass such argument.
 
371
 
 
372
  RETURN VALUE
 
373
    Seconds since epoch time representation.
 
374
*/
 
375
static time_t
 
376
sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec)
 
377
{
 
378
  /* Guard against time_t overflow (on system with 32 bit time_t) */
 
379
  assert(!(year == TIMESTAMP_MAX_YEAR && mon == 1 && mday > 17));
 
380
#ifndef WE_WANT_TO_HANDLE_UNORMALIZED_DATES
 
381
  /*
 
382
    It turns out that only whenever month is normalized or unnormalized
 
383
    plays role.
 
384
  */
 
385
  assert(mon > 0 && mon < 13);
 
386
  long days= year * DAYS_PER_NYEAR - EPOCH_YEAR * DAYS_PER_NYEAR +
 
387
             LEAPS_THRU_END_OF(year - 1) -
 
388
             LEAPS_THRU_END_OF(EPOCH_YEAR - 1);
 
389
  days+= mon_starts[isleap(year)][mon - 1];
 
390
#else
 
391
  long norm_month= (mon - 1) % MONS_PER_YEAR;
 
392
  long a_year= year + (mon - 1)/MONS_PER_YEAR - (int)(norm_month < 0);
 
393
  long days= a_year * DAYS_PER_NYEAR - EPOCH_YEAR * DAYS_PER_NYEAR +
 
394
             LEAPS_THRU_END_OF(a_year - 1) -
 
395
             LEAPS_THRU_END_OF(EPOCH_YEAR - 1);
 
396
  days+= mon_starts[isleap(a_year)]
 
397
                    [norm_month + (norm_month < 0 ? MONS_PER_YEAR : 0)];
 
398
#endif
 
399
  days+= mday - 1;
 
400
 
 
401
  return ((days * HOURS_PER_DAY + hour) * MINS_PER_HOUR + min) *
 
402
         SECS_PER_MIN + sec;
 
403
}
 
404
 
 
405
/*
 
406
  Converts local time in broken down DRIZZLE_TIME representation to time_t
 
407
  representation.
 
408
 
 
409
  SYNOPSIS
 
410
    TIME_to_gmt_sec()
 
411
      t               - pointer to structure for broken down represenatation
 
412
      sp              - pointer to struct with time zone description
 
413
      in_dst_time_gap - pointer to bool which is set to true if datetime
 
414
                        value passed doesn't really exist (i.e. falls into
 
415
                        spring time-gap) and is not touched otherwise.
 
416
 
 
417
  DESCRIPTION
 
418
    This is mktime analog for MySQL. It is essentially different
 
419
    from mktime (or hypotetical my_mktime) because:
 
420
    - It has no idea about tm_isdst member so if it
 
421
      has two answers it will give the smaller one
 
422
    - If we are in spring time gap then it will return
 
423
      beginning of the gap
 
424
    - It can give wrong results near the ends of time_t due to
 
425
      overflows, but we are safe since in MySQL we will never
 
426
      call this function for such dates (its restriction for year
 
427
      between 1970 and 2038 gives us several days of reserve).
 
428
    - By default it doesn't support un-normalized input. But if
 
429
      sec_since_epoch() function supports un-normalized dates
 
430
      then this function should handle un-normalized input right,
 
431
      altough it won't normalize structure TIME.
 
432
 
 
433
    Traditional approach to problem of conversion from broken down
 
434
    representation to time_t is iterative. Both elsie's and glibc
 
435
    implementation try to guess what time_t value should correspond to
 
436
    this broken-down value. They perform localtime_r function on their
 
437
    guessed value and then calculate the difference and try to improve
 
438
    their guess. Elsie's code guesses time_t value in bit by bit manner,
 
439
    Glibc's code tries to add difference between broken-down value
 
440
    corresponding to guess and target broken-down value to current guess.
 
441
    It also uses caching of last found correction... So Glibc's approach
 
442
    is essentially faster but introduces some undetermenism (in case if
 
443
    is_dst member of broken-down representation (tm struct) is not known
 
444
    and we have two possible answers).
 
445
 
 
446
    We use completely different approach. It is better since it is both
 
447
    faster than iterative implementations and fully determenistic. If you
 
448
    look at time_t to DRIZZLE_TIME conversion then you'll find that it consist
 
449
    of two steps:
 
450
    The first is calculating shifted time_t value and the second - TIME
 
451
    calculation from shifted time_t value (well it is a bit simplified
 
452
    picture). The part in which we are interested in is time_t -> shifted
 
453
    time_t conversion. It is piecewise linear function which is defined
 
454
    by combination of transition times as break points and times offset
 
455
    as changing function parameter. The possible inverse function for this
 
456
    converison would be ambiguos but with MySQL's restrictions we can use
 
457
    some function which is the same as inverse function on unambigiuos
 
458
    ranges and coincides with one of branches of inverse function in
 
459
    other ranges. Thus we just need to build table which will determine
 
460
    this shifted time_t -> time_t conversion similar to existing
 
461
    (time_t -> shifted time_t table). We do this in
 
462
    prepare_tz_info function.
 
463
 
 
464
  TODO
 
465
    If we can even more improve this function. For doing this we will need to
 
466
    build joined map of transitions and leap corrections for gmt_sec_to_TIME()
 
467
    function (similar to revts/revtis). Under realistic assumptions about
 
468
    frequency of transitions we can use the same array for TIME_to_gmt_sec().
 
469
    We need to implement special version of binary search for this. Such step
 
470
    will be beneficial to CPU cache since we will decrease data-set used for
 
471
    conversion twice.
 
472
 
 
473
  RETURN VALUE
 
474
    Seconds in UTC since Epoch.
 
475
    0 in case of error.
 
476
*/
 
477
static time_t
 
478
TIME_to_gmt_sec(const DRIZZLE_TIME *t, const TIME_ZONE_INFO *sp,
 
479
                bool *in_dst_time_gap)
 
480
{
 
481
  time_t local_t;
 
482
  uint32_t saved_seconds;
 
483
  uint32_t i;
 
484
  int shift= 0;
 
485
 
 
486
  if (!validate_timestamp_range(t))
 
487
    return(0);
 
488
 
 
489
 
 
490
  /* We need this for correct leap seconds handling */
 
491
  if (t->second < SECS_PER_MIN)
 
492
    saved_seconds= 0;
 
493
  else
 
494
    saved_seconds= t->second;
 
495
 
 
496
  /*
 
497
    NOTE: to convert full time_t range we do a shift of the
 
498
    boundary dates here to avoid overflow of time_t.
 
499
    We use alike approach in my_system_gmt_sec().
 
500
 
 
501
    However in that function we also have to take into account
 
502
    overflow near 0 on some platforms. That's because my_system_gmt_sec
 
503
    uses localtime_r(), which doesn't work with negative values correctly
 
504
    on platforms with unsigned time_t (QNX). Here we don't use localtime()
 
505
    => we negative values of local_t are ok.
 
506
  */
 
507
 
 
508
  if ((t->year == TIMESTAMP_MAX_YEAR) && (t->month == 1) && t->day > 4)
 
509
  {
 
510
    /*
 
511
      We will pass (t->day - shift) to sec_since_epoch(), and
 
512
      want this value to be a positive number, so we shift
 
513
      only dates > 4.01.2038 (to avoid owerflow).
 
514
    */
 
515
    shift= 2;
 
516
  }
 
517
 
 
518
 
 
519
  local_t= sec_since_epoch(t->year, t->month, (t->day - shift),
 
520
                           t->hour, t->minute,
 
521
                           saved_seconds ? 0 : t->second);
 
522
 
 
523
  /* We have at least one range */
 
524
  assert(sp->revcnt >= 1);
 
525
 
 
526
  if (local_t < sp->revts[0] || local_t > sp->revts[sp->revcnt])
 
527
  {
 
528
    /*
 
529
      This means that source time can't be represented as time_t due to
 
530
      limited time_t range.
 
531
    */
 
532
    return(0);
 
533
  }
 
534
 
 
535
  /* binary search for our range */
 
536
  i= find_time_range(local_t, sp->revts, sp->revcnt);
 
537
 
 
538
  /*
 
539
    As there are no offset switches at the end of TIMESTAMP range,
 
540
    we could simply check for overflow here (and don't need to bother
 
541
    about DST gaps etc)
 
542
  */
 
543
  if (shift)
 
544
  {
 
545
    if (local_t > (time_t) (TIMESTAMP_MAX_VALUE - shift * SECS_PER_DAY +
 
546
                            sp->revtis[i].rt_offset - saved_seconds))
 
547
    {
 
548
      return(0);                           /* time_t overflow */
 
549
    }
 
550
    local_t+= shift * SECS_PER_DAY;
 
551
  }
 
552
 
 
553
  if (sp->revtis[i].rt_type)
 
554
  {
 
555
    /*
 
556
      Oops! We are in spring time gap.
 
557
      May be we should return error here?
 
558
      Now we are returning time_t value corresponding to the
 
559
      beginning of the gap.
 
560
    */
 
561
    *in_dst_time_gap= 1;
 
562
    local_t= sp->revts[i] - sp->revtis[i].rt_offset + saved_seconds;
 
563
  }
 
564
  else
 
565
    local_t= local_t - sp->revtis[i].rt_offset + saved_seconds;
 
566
 
 
567
  /* check for TIMESTAMP_MAX_VALUE was already done above */
 
568
  if (local_t < TIMESTAMP_MIN_VALUE)
 
569
    local_t= 0;
 
570
 
 
571
  return(local_t);
 
572
}
 
573
 
 
574
 
 
575
/*
 
576
  End of elsie derived code.
 
577
*/
 
578
#endif /* !defined(TZINFO2SQL) */
 
579
 
 
580
 
 
581
/*
 
582
  String with names of SYSTEM time zone.
 
583
*/
35
584
static const String tz_SYSTEM_name("SYSTEM", 6, &my_charset_utf8_general_ci);
36
585
 
37
586
 
38
 
/**
39
 
 * Instance of this class represents local time zone used on this system
40
 
 * (specified by TZ environment variable or via any other system mechanism).
41
 
 * It uses system functions (localtime_r, my_system_gmt_sec) for conversion
42
 
 * and is always available. Because of this it is used by default - if there
43
 
 * were no explicit time zone specified. On the other hand because of this
44
 
 * conversion methods provided by this class is significantly slower and
45
 
 * possibly less multi-threaded-friendly than corresponding Time_zone_db
46
 
 * methods so the latter should be preffered there it is possible.
47
 
 */
 
587
/*
 
588
  Instance of this class represents local time zone used on this system
 
589
  (specified by TZ environment variable or via any other system mechanism).
 
590
  It uses system functions (localtime_r, my_system_gmt_sec) for conversion
 
591
  and is always available. Because of this it is used by default - if there
 
592
  were no explicit time zone specified. On the other hand because of this
 
593
  conversion methods provided by this class is significantly slower and
 
594
  possibly less multi-threaded-friendly than corresponding Time_zone_db
 
595
  methods so the latter should be preffered there it is possible.
 
596
*/
48
597
class Time_zone_system : public Time_zone
49
598
{
50
599
public:
56
605
};
57
606
 
58
607
 
59
 
/**
60
 
 * @brief
61
 
 * Converts local time in system time zone in DRIZZLE_TIME representation
62
 
 * to its time_t representation.
63
 
 *
64
 
 * @details
65
 
 * This method uses system function (localtime_r()) for conversion
66
 
 * local time in system time zone in DRIZZLE_TIME structure to its time_t
67
 
 * representation. Unlike the same function for Time_zone_db class
68
 
 * it it won't handle unnormalized input properly. Still it will
69
 
 * return lowest possible time_t in case of ambiguity or if we
70
 
 * provide time corresponding to the time-gap.
71
 
 *
72
 
 * You should call init_time() function before using this function.
73
 
 *
74
 
 * @param   t               pointer to DRIZZLE_TIME structure with local time in
75
 
 *                          broken-down representation.
76
 
 * @param   in_dst_time_gap pointer to bool which is set to true if datetime
77
 
 *                          value passed doesn't really exist (i.e. falls into
78
 
 *                          spring time-gap) and is not touched otherwise.
79
 
 *
80
 
 * @return
81
 
 * Corresponding time_t value or 0 in case of error
82
 
 */
 
608
/*
 
609
  Converts local time in system time zone in DRIZZLE_TIME representation
 
610
  to its time_t representation.
 
611
 
 
612
  SYNOPSIS
 
613
    TIME_to_gmt_sec()
 
614
      t               - pointer to DRIZZLE_TIME structure with local time in
 
615
                        broken-down representation.
 
616
      in_dst_time_gap - pointer to bool which is set to true if datetime
 
617
                        value passed doesn't really exist (i.e. falls into
 
618
                        spring time-gap) and is not touched otherwise.
 
619
 
 
620
  DESCRIPTION
 
621
    This method uses system function (localtime_r()) for conversion
 
622
    local time in system time zone in DRIZZLE_TIME structure to its time_t
 
623
    representation. Unlike the same function for Time_zone_db class
 
624
    it it won't handle unnormalized input properly. Still it will
 
625
    return lowest possible time_t in case of ambiguity or if we
 
626
    provide time corresponding to the time-gap.
 
627
 
 
628
    You should call init_time() function before using this function.
 
629
 
 
630
  RETURN VALUE
 
631
    Corresponding time_t value or 0 in case of error
 
632
*/
83
633
time_t
84
634
Time_zone_system::TIME_to_gmt_sec(const DRIZZLE_TIME *t, bool *in_dst_time_gap) const
85
635
{
88
638
}
89
639
 
90
640
 
91
 
/**
92
 
 * @brief
93
 
 * Converts time from UTC seconds since Epoch (time_t) representation
94
 
 * to system local time zone broken-down representation.
95
 
 *
96
 
 * @param    tmp   pointer to DRIZZLE_TIME structure to fill-in
97
 
 * @param    t     time_t value to be converted
98
 
 *
99
 
 * Note: We assume that value passed to this function will fit into time_t range
100
 
 * supported by localtime_r. This conversion is putting restriction on
101
 
 * TIMESTAMP range in MySQL. If we can get rid of SYSTEM time zone at least
102
 
 * for interaction with client then we can extend TIMESTAMP range down to
103
 
 * the 1902 easily.
104
 
 */
 
641
/*
 
642
  Converts time from UTC seconds since Epoch (time_t) representation
 
643
  to system local time zone broken-down representation.
 
644
 
 
645
  SYNOPSIS
 
646
    gmt_sec_to_TIME()
 
647
      tmp - pointer to DRIZZLE_TIME structure to fill-in
 
648
      t   - time_t value to be converted
 
649
 
 
650
  NOTE
 
651
    We assume that value passed to this function will fit into time_t range
 
652
    supported by localtime_r. This conversion is putting restriction on
 
653
    TIMESTAMP range in MySQL. If we can get rid of SYSTEM time zone at least
 
654
    for interaction with client then we can extend TIMESTAMP range down to
 
655
    the 1902 easily.
 
656
*/
105
657
void
106
658
Time_zone_system::gmt_sec_to_TIME(DRIZZLE_TIME *tmp, time_t t) const
107
659
{
114
666
}
115
667
 
116
668
 
117
 
/**
118
 
 * @brief
119
 
 * Get name of time zone
120
 
 *
121
 
 * @return
122
 
 * Name of time zone as String
123
 
 */
 
669
/*
 
670
  Get name of time zone
 
671
 
 
672
  SYNOPSIS
 
673
    get_name()
 
674
 
 
675
  RETURN VALUE
 
676
    Name of time zone as String
 
677
*/
124
678
const String *
125
679
Time_zone_system::get_name() const
126
680
{
127
681
  return &tz_SYSTEM_name;
128
682
}
129
683
 
 
684
 
 
685
/*
 
686
  Instance of this class represents UTC time zone. It uses system gmtime_r
 
687
  function for conversions and is always available. It is used only for
 
688
  time_t -> DRIZZLE_TIME conversions in various UTC_...  functions, it is not
 
689
  intended for DRIZZLE_TIME -> time_t conversions and shouldn't be exposed to user.
 
690
*/
 
691
class Time_zone_utc : public Time_zone
 
692
{
 
693
public:
 
694
  Time_zone_utc() {}                          /* Remove gcc warning */
 
695
  virtual time_t TIME_to_gmt_sec(const DRIZZLE_TIME *t,
 
696
                                    bool *in_dst_time_gap) const;
 
697
  virtual void gmt_sec_to_TIME(DRIZZLE_TIME *tmp, time_t t) const;
 
698
  virtual const String * get_name() const;
 
699
};
 
700
 
 
701
 
 
702
/*
 
703
  Convert UTC time from DRIZZLE_TIME representation to its time_t representation.
 
704
 
 
705
  SYNOPSIS
 
706
    TIME_to_gmt_sec()
 
707
      t               - pointer to DRIZZLE_TIME structure with local time
 
708
                        in broken-down representation.
 
709
      in_dst_time_gap - pointer to bool which is set to true if datetime
 
710
                        value passed doesn't really exist (i.e. falls into
 
711
                        spring time-gap) and is not touched otherwise.
 
712
 
 
713
  DESCRIPTION
 
714
    Since Time_zone_utc is used only internally for time_t -> TIME
 
715
    conversions, this function of Time_zone interface is not implemented for
 
716
    this class and should not be called.
 
717
 
 
718
  RETURN VALUE
 
719
    0
 
720
*/
 
721
time_t
 
722
Time_zone_utc::TIME_to_gmt_sec(const DRIZZLE_TIME *t __attribute__((unused)),
 
723
                               bool *in_dst_time_gap __attribute__((unused))) const
 
724
{
 
725
  /* Should be never called */
 
726
  assert(0);
 
727
  return 0;
 
728
}
 
729
 
 
730
 
 
731
/*
 
732
  Converts time from UTC seconds since Epoch (time_t) representation
 
733
  to broken-down representation (also in UTC).
 
734
 
 
735
  SYNOPSIS
 
736
    gmt_sec_to_TIME()
 
737
      tmp - pointer to DRIZZLE_TIME structure to fill-in
 
738
      t   - time_t value to be converted
 
739
 
 
740
  NOTE
 
741
    See note for apropriate Time_zone_system method.
 
742
*/
 
743
void
 
744
Time_zone_utc::gmt_sec_to_TIME(DRIZZLE_TIME *tmp, time_t t) const
 
745
{
 
746
  struct tm tmp_tm;
 
747
  time_t tmp_t= (time_t)t;
 
748
  gmtime_r(&tmp_t, &tmp_tm);
 
749
  localtime_to_TIME(tmp, &tmp_tm);
 
750
  tmp->time_type= DRIZZLE_TIMESTAMP_DATETIME;
 
751
}
 
752
 
 
753
 
 
754
/*
 
755
  Get name of time zone
 
756
 
 
757
  SYNOPSIS
 
758
    get_name()
 
759
 
 
760
  DESCRIPTION
 
761
    Since Time_zone_utc is used only internally by SQL's UTC_* functions it
 
762
    is not accessible directly, and hence this function of Time_zone
 
763
    interface is not implemented for this class and should not be called.
 
764
 
 
765
  RETURN VALUE
 
766
    0
 
767
*/
 
768
const String *
 
769
Time_zone_utc::get_name() const
 
770
{
 
771
  /* Should be never called */
 
772
  assert(0);
 
773
  return 0;
 
774
}
 
775
 
 
776
 
 
777
/*
 
778
  Instance of this class represents some time zone which is
 
779
  described in mysql.time_zone family of tables.
 
780
*/
 
781
class Time_zone_db : public Time_zone
 
782
{
 
783
public:
 
784
  Time_zone_db(TIME_ZONE_INFO *tz_info_arg, const String * tz_name_arg);
 
785
  virtual time_t TIME_to_gmt_sec(const DRIZZLE_TIME *t,
 
786
                                    bool *in_dst_time_gap) const;
 
787
  virtual void gmt_sec_to_TIME(DRIZZLE_TIME *tmp, time_t t) const;
 
788
  virtual const String * get_name() const;
 
789
private:
 
790
  TIME_ZONE_INFO *tz_info;
 
791
  const String *tz_name;
 
792
};
 
793
 
 
794
 
 
795
/*
 
796
  Initializes object representing time zone described by mysql.time_zone
 
797
  tables.
 
798
 
 
799
  SYNOPSIS
 
800
    Time_zone_db()
 
801
      tz_info_arg - pointer to TIME_ZONE_INFO structure which is filled
 
802
                    according to db or other time zone description
 
803
                    (for example by my_tz_init()).
 
804
                    Several Time_zone_db instances can share one
 
805
                    TIME_ZONE_INFO structure.
 
806
      tz_name_arg - name of time zone.
 
807
*/
 
808
Time_zone_db::Time_zone_db(TIME_ZONE_INFO *tz_info_arg,
 
809
                           const String *tz_name_arg):
 
810
  tz_info(tz_info_arg), tz_name(tz_name_arg)
 
811
{
 
812
}
 
813
 
 
814
 
 
815
/*
 
816
  Converts local time in time zone described from TIME
 
817
  representation to its time_t representation.
 
818
 
 
819
  SYNOPSIS
 
820
    TIME_to_gmt_sec()
 
821
      t               - pointer to DRIZZLE_TIME structure with local time
 
822
                        in broken-down representation.
 
823
      in_dst_time_gap - pointer to bool which is set to true if datetime
 
824
                        value passed doesn't really exist (i.e. falls into
 
825
                        spring time-gap) and is not touched otherwise.
 
826
 
 
827
  DESCRIPTION
 
828
    Please see ::TIME_to_gmt_sec for function description and
 
829
    parameter restrictions.
 
830
 
 
831
  RETURN VALUE
 
832
    Corresponding time_t value or 0 in case of error
 
833
*/
 
834
time_t
 
835
Time_zone_db::TIME_to_gmt_sec(const DRIZZLE_TIME *t, bool *in_dst_time_gap) const
 
836
{
 
837
  return ::TIME_to_gmt_sec(t, tz_info, in_dst_time_gap);
 
838
}
 
839
 
 
840
 
 
841
/*
 
842
  Converts time from UTC seconds since Epoch (time_t) representation
 
843
  to local time zone described in broken-down representation.
 
844
 
 
845
  SYNOPSIS
 
846
    gmt_sec_to_TIME()
 
847
      tmp - pointer to DRIZZLE_TIME structure to fill-in
 
848
      t   - time_t value to be converted
 
849
*/
 
850
void
 
851
Time_zone_db::gmt_sec_to_TIME(DRIZZLE_TIME *tmp, time_t t) const
 
852
{
 
853
  ::gmt_sec_to_TIME(tmp, t, tz_info);
 
854
}
 
855
 
 
856
 
 
857
/*
 
858
  Get name of time zone
 
859
 
 
860
  SYNOPSIS
 
861
    get_name()
 
862
 
 
863
  RETURN VALUE
 
864
    Name of time zone as ASCIIZ-string
 
865
*/
 
866
const String *
 
867
Time_zone_db::get_name() const
 
868
{
 
869
  return tz_name;
 
870
}
 
871
 
 
872
 
 
873
/*
 
874
  Instance of this class represents time zone which
 
875
  was specified as offset from UTC.
 
876
*/
 
877
class Time_zone_offset : public Time_zone
 
878
{
 
879
public:
 
880
  Time_zone_offset(long tz_offset_arg);
 
881
  virtual time_t TIME_to_gmt_sec(const DRIZZLE_TIME *t,
 
882
                                    bool *in_dst_time_gap) const;
 
883
  virtual void   gmt_sec_to_TIME(DRIZZLE_TIME *tmp, time_t t) const;
 
884
  virtual const String * get_name() const;
 
885
  /*
 
886
    This have to be public because we want to be able to access it from
 
887
    my_offset_tzs_get_key() function
 
888
  */
 
889
  long offset;
 
890
private:
 
891
  /* Extra reserve because of snprintf */
 
892
  char name_buff[7+16];
 
893
  String name;
 
894
};
 
895
 
 
896
 
 
897
/*
 
898
  Initializes object representing time zone described by its offset from UTC.
 
899
 
 
900
  SYNOPSIS
 
901
    Time_zone_offset()
 
902
      tz_offset_arg - offset from UTC in seconds.
 
903
                      Positive for direction to east.
 
904
*/
 
905
Time_zone_offset::Time_zone_offset(long tz_offset_arg):
 
906
  offset(tz_offset_arg)
 
907
{
 
908
  uint32_t hours= abs((int)(offset / SECS_PER_HOUR));
 
909
  uint32_t minutes= abs((int)(offset % SECS_PER_HOUR / SECS_PER_MIN));
 
910
  ulong length= snprintf(name_buff, sizeof(name_buff), "%s%02d:%02d",
 
911
                         (offset>=0) ? "+" : "-", hours, minutes);
 
912
  name.set(name_buff, length, &my_charset_utf8_general_ci);
 
913
}
 
914
 
 
915
 
 
916
/*
 
917
  Converts local time in time zone described as offset from UTC
 
918
  from DRIZZLE_TIME representation to its time_t representation.
 
919
 
 
920
  SYNOPSIS
 
921
    TIME_to_gmt_sec()
 
922
      t               - pointer to DRIZZLE_TIME structure with local time
 
923
                        in broken-down representation.
 
924
      in_dst_time_gap - pointer to bool which should be set to true if
 
925
                        datetime  value passed doesn't really exist
 
926
                        (i.e. falls into spring time-gap) and is not
 
927
                        touched otherwise.
 
928
                        It is not really used in this class.
 
929
 
 
930
  RETURN VALUE
 
931
    Corresponding time_t value or 0 in case of error
 
932
*/
 
933
time_t
 
934
Time_zone_offset::TIME_to_gmt_sec(const DRIZZLE_TIME *t,
 
935
                                  bool *in_dst_time_gap __attribute__((unused))) const
 
936
{
 
937
  time_t local_t;
 
938
  int shift= 0;
 
939
 
 
940
  /*
 
941
    Check timestamp range.we have to do this as calling function relies on
 
942
    us to make all validation checks here.
 
943
  */
 
944
  if (!validate_timestamp_range(t))
 
945
    return 0;
 
946
 
 
947
  /*
 
948
    Do a temporary shift of the boundary dates to avoid
 
949
    overflow of time_t if the time value is near it's
 
950
    maximum range
 
951
  */
 
952
  if ((t->year == TIMESTAMP_MAX_YEAR) && (t->month == 1) && t->day > 4)
 
953
    shift= 2;
 
954
 
 
955
  local_t= sec_since_epoch(t->year, t->month, (t->day - shift),
 
956
                           t->hour, t->minute, t->second) -
 
957
           offset;
 
958
 
 
959
  if (shift)
 
960
  {
 
961
    /* Add back the shifted time */
 
962
    local_t+= shift * SECS_PER_DAY;
 
963
  }
 
964
 
 
965
  if (local_t >= TIMESTAMP_MIN_VALUE && local_t <= TIMESTAMP_MAX_VALUE)
 
966
    return local_t;
 
967
 
 
968
  /* range error*/
 
969
  return 0;
 
970
}
 
971
 
 
972
 
 
973
/*
 
974
  Converts time from UTC seconds since Epoch (time_t) representation
 
975
  to local time zone described as offset from UTC and in broken-down
 
976
  representation.
 
977
 
 
978
  SYNOPSIS
 
979
    gmt_sec_to_TIME()
 
980
      tmp - pointer to DRIZZLE_TIME structure to fill-in
 
981
      t   - time_t value to be converted
 
982
*/
 
983
void
 
984
Time_zone_offset::gmt_sec_to_TIME(DRIZZLE_TIME *tmp, time_t t) const
 
985
{
 
986
  sec_to_TIME(tmp, t, offset);
 
987
}
 
988
 
 
989
 
 
990
/*
 
991
  Get name of time zone
 
992
 
 
993
  SYNOPSIS
 
994
    get_name()
 
995
 
 
996
  RETURN VALUE
 
997
    Name of time zone as pointer to String object
 
998
*/
 
999
const String *
 
1000
Time_zone_offset::get_name() const
 
1001
{
 
1002
  return &name;
 
1003
}
 
1004
 
 
1005
 
 
1006
static Time_zone_utc tz_UTC;
130
1007
static Time_zone_system tz_SYSTEM;
 
1008
static Time_zone_offset tz_OFFSET0(0);
131
1009
 
 
1010
Time_zone *my_tz_OFFSET0= &tz_OFFSET0;
 
1011
Time_zone *my_tz_UTC= &tz_UTC;
132
1012
Time_zone *my_tz_SYSTEM= &tz_SYSTEM;
133
1013
 
134
 
 
135
 
/**
136
 
 * @brief
137
 
 * Initialize time zone support infrastructure.
138
 
 *
139
 
 * @details
140
 
 * This function will init memory structures needed for time zone support,
141
 
 * it will register mandatory SYSTEM time zone in them. It will try to open
142
 
 * mysql.time_zone* tables and load information about default time zone and
143
 
 * information which further will be shared among all time zones loaded.
144
 
 * If system tables with time zone descriptions don't exist it won't fail
145
 
 * (unless default_tzname is time zone from tables). If bootstrap parameter
146
 
 * is true then this routine assumes that we are in bootstrap mode and won't
147
 
 * load time zone descriptions unless someone specifies default time zone
148
 
 * which is supposedly stored in those tables.
149
 
 * It'll also set default time zone if it is specified.
150
 
 *
151
 
 * @param   session            current thread object
152
 
 * @param   default_tzname     default time zone or 0 if none.
153
 
 * @param   bootstrap          indicates whenever we are in bootstrap mode
154
 
 *
155
 
 * @return
156
 
 *  0 - ok
157
 
 *  1 - Error
158
 
 */
 
1014
class Tz_names_entry: public Sql_alloc
 
1015
{
 
1016
public:
 
1017
  String name;
 
1018
  Time_zone *tz;
 
1019
};
 
1020
 
 
1021
 
 
1022
/*
 
1023
  Initialize time zone support infrastructure.
 
1024
 
 
1025
  SYNOPSIS
 
1026
    my_tz_init()
 
1027
      session            - current thread object
 
1028
      default_tzname - default time zone or 0 if none.
 
1029
      bootstrap      - indicates whenever we are in bootstrap mode
 
1030
 
 
1031
  DESCRIPTION
 
1032
    This function will init memory structures needed for time zone support,
 
1033
    it will register mandatory SYSTEM time zone in them. It will try to open
 
1034
    mysql.time_zone* tables and load information about default time zone and
 
1035
    information which further will be shared among all time zones loaded.
 
1036
    If system tables with time zone descriptions don't exist it won't fail
 
1037
    (unless default_tzname is time zone from tables). If bootstrap parameter
 
1038
    is true then this routine assumes that we are in bootstrap mode and won't
 
1039
    load time zone descriptions unless someone specifies default time zone
 
1040
    which is supposedly stored in those tables.
 
1041
    It'll also set default time zone if it is specified.
 
1042
 
 
1043
  RETURN VALUES
 
1044
    0 - ok
 
1045
    1 - Error
 
1046
*/
159
1047
bool
160
1048
my_tz_init(Session *session, const char *default_tzname)
161
1049
{
179
1067
  return false;
180
1068
}
181
1069
 
182
 
/**
183
 
 * @brief
184
 
 * Get Time_zone object for specified time zone.
185
 
 *
186
 
 * @todo
187
 
 * Not implemented yet. This needs to hook into some sort of OS system call.
188
 
 */
 
1070
 
 
1071
/*
 
1072
  Free resources used by time zone support infrastructure.
 
1073
*/
 
1074
 
 
1075
void my_tz_free()
 
1076
{
 
1077
}
 
1078
 
 
1079
 
 
1080
/*
 
1081
  Parse string that specifies time zone as offset from UTC.
 
1082
 
 
1083
  SYNOPSIS
 
1084
    str_to_offset()
 
1085
      str    - pointer to string which contains offset
 
1086
      length - length of string
 
1087
      offset - out parameter for storing found offset in seconds.
 
1088
 
 
1089
  DESCRIPTION
 
1090
    This function parses string which contains time zone offset
 
1091
    in form similar to '+10:00' and converts found value to
 
1092
    seconds from UTC form (east is positive).
 
1093
 
 
1094
  RETURN VALUE
 
1095
    0 - Ok
 
1096
    1 - String doesn't contain valid time zone offset
 
1097
*/
 
1098
bool
 
1099
str_to_offset(const char *str, uint32_t length, long *offset)
 
1100
{
 
1101
  const char *end= str + length;
 
1102
  bool negative;
 
1103
  ulong number_tmp;
 
1104
  long offset_tmp;
 
1105
 
 
1106
  if (length < 4)
 
1107
    return 1;
 
1108
 
 
1109
  if (*str == '+')
 
1110
    negative= 0;
 
1111
  else if (*str == '-')
 
1112
    negative= 1;
 
1113
  else
 
1114
    return 1;
 
1115
  str++;
 
1116
 
 
1117
  number_tmp= 0;
 
1118
 
 
1119
  while (str < end && my_isdigit(&my_charset_utf8_general_ci, *str))
 
1120
  {
 
1121
    number_tmp= number_tmp*10 + *str - '0';
 
1122
    str++;
 
1123
  }
 
1124
 
 
1125
  if (str + 1 >= end || *str != ':')
 
1126
    return 1;
 
1127
  str++;
 
1128
 
 
1129
  offset_tmp = number_tmp * MINS_PER_HOUR; number_tmp= 0;
 
1130
 
 
1131
  while (str < end && my_isdigit(&my_charset_utf8_general_ci, *str))
 
1132
  {
 
1133
    number_tmp= number_tmp * 10 + *str - '0';
 
1134
    str++;
 
1135
  }
 
1136
 
 
1137
  if (str != end)
 
1138
    return 1;
 
1139
 
 
1140
  offset_tmp= (offset_tmp + number_tmp) * SECS_PER_MIN;
 
1141
 
 
1142
  if (negative)
 
1143
    offset_tmp= -offset_tmp;
 
1144
 
 
1145
  /*
 
1146
    Check if offset is in range prescribed by standard
 
1147
    (from -12:59 to 13:00).
 
1148
  */
 
1149
 
 
1150
  if (number_tmp > 59 || offset_tmp < -13 * SECS_PER_HOUR + 1 ||
 
1151
      offset_tmp > 13 * SECS_PER_HOUR)
 
1152
    return 1;
 
1153
 
 
1154
  *offset= offset_tmp;
 
1155
 
 
1156
  return 0;
 
1157
}
 
1158
 
 
1159
 
 
1160
/*
 
1161
  Get Time_zone object for specified time zone.
 
1162
 
 
1163
  Not implemented yet. This needs to hook into some sort of OS system call.
 
1164
 
 
1165
*/
189
1166
Time_zone *
190
 
my_tz_find(Session *,
191
 
           const String *)
 
1167
my_tz_find(Session *session __attribute__((unused)),
 
1168
           const String *name __attribute__((unused)))
192
1169
{
193
1170
  return NULL;
194
1171
}
195
 
 
196
 
} /* namespace drizzled */