~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/tztime.cc

  • Committer: Monty Taylor
  • Date: 2008-10-16 09:12:23 UTC
  • mto: (511.1.6 codestyle)
  • mto: This revision was merged to the branch mainline in revision 521.
  • Revision ID: monty@inaugust.com-20081016091223-17ngih0qu9vssjs3
We pass -Wunused-macros now!

Show diffs side-by-side

added added

removed removed

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