~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to server/tztime.cc

Merge/fix in FAQ.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
#pragma implementation                          // gcc: Class implementation
18
18
#endif
19
19
 
20
 
#include <drizzled/server_includes.h>
 
20
#include <my_global.h>
 
21
#include "mysql_priv.h"
 
22
#include <my_time.h>
 
23
 
21
24
#include "tzfile.h"
 
25
#include <m_string.h>
22
26
 
23
27
/* Structure describing local time type (e.g. Moscow summer time (MSD)) */
24
28
typedef struct ttinfo
25
29
{
26
30
  long tt_gmtoff; // Offset from UTC in seconds
27
 
  uint32_t tt_isdst;   // Is daylight saving time or not. Used to set tm_isdst
28
 
  uint32_t tt_abbrind; // Index of start of abbreviation for this time type.
 
31
  uint tt_isdst;   // Is daylight saving time or not. Used to set tm_isdst
 
32
  uint tt_abbrind; // Index of start of abbreviation for this time type.
29
33
  /*
30
34
    We don't use tt_ttisstd and tt_ttisgmt members of original elsie-code
31
35
    struct since we don't support POSIX-style TZ descriptions in variables.
41
45
 
42
46
/*
43
47
  Structure with information describing ranges of my_time_t shifted to local
44
 
  time (my_time_t + offset). Used for local DRIZZLE_TIME -> my_time_t conversion.
 
48
  time (my_time_t + offset). Used for local MYSQL_TIME -> my_time_t conversion.
45
49
  See comments for TIME_to_gmt_sec() for more info.
46
50
*/
47
51
typedef struct revtinfo
48
52
{
49
53
  long rt_offset; // Offset of local time from UTC in seconds
50
 
  uint32_t rt_type;    // Type of period 0 - Normal period. 1 - Spring time-gap
 
54
  uint rt_type;    // Type of period 0 - Normal period. 1 - Spring time-gap
51
55
} REVT_INFO;
52
56
 
53
57
#ifdef TZNAME_MAX
63
67
*/
64
68
typedef struct st_time_zone_info
65
69
{
66
 
  uint32_t leapcnt;  // Number of leap-second corrections
67
 
  uint32_t timecnt;  // Number of transitions between time types
68
 
  uint32_t typecnt;  // Number of local time types
69
 
  uint32_t charcnt;  // Number of characters used for abbreviations
70
 
  uint32_t revcnt;   // Number of transition descr. for TIME->my_time_t conversion
 
70
  uint leapcnt;  // Number of leap-second corrections
 
71
  uint timecnt;  // Number of transitions between time types
 
72
  uint typecnt;  // Number of local time types
 
73
  uint charcnt;  // Number of characters used for abbreviations
 
74
  uint revcnt;   // Number of transition descr. for TIME->my_time_t conversion
71
75
  /* The following are dynamical arrays are allocated in MEM_ROOT */
72
76
  my_time_t *ats;       // Times of transitions between time types
73
 
  unsigned char *types; // Local time types for transitions
 
77
  uchar *types; // Local time types for transitions
74
78
  TRAN_TYPE_INFO *ttis; // Local time types descriptions
75
79
  /* Storage for local time types abbreviations. They are stored as ASCIIZ */
76
80
  char *chars;
97
101
 
98
102
#if !defined(TZINFO2SQL)
99
103
 
100
 
static const uint32_t mon_lengths[2][MONS_PER_YEAR]=
 
104
static const uint mon_lengths[2][MONS_PER_YEAR]=
101
105
{
102
106
  { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
103
107
  { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
104
108
};
105
109
 
106
 
static const uint32_t mon_starts[2][MONS_PER_YEAR]=
 
110
static const uint mon_starts[2][MONS_PER_YEAR]=
107
111
{
108
112
  { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
109
113
  { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
110
114
};
111
115
 
112
 
static const uint32_t year_lengths[2]=
 
116
static const uint year_lengths[2]=
113
117
{
114
118
  DAYS_PER_NYEAR, DAYS_PER_LYEAR
115
119
};
128
132
      offset - local time zone offset
129
133
 
130
134
  DESCRIPTION
131
 
    Convert my_time_t with offset to DRIZZLE_TIME struct. Differs from timesub
 
135
    Convert my_time_t with offset to MYSQL_TIME struct. Differs from timesub
132
136
    (from elsie code) because doesn't contain any leap correction and
133
137
    TM_GMTOFF and is_dst setting and contains some MySQL specific
134
138
    initialization. Funny but with removing of these we almost have
135
139
    glibc's offtime function.
136
140
*/
137
141
static void
138
 
sec_to_TIME(DRIZZLE_TIME * tmp, my_time_t t, long offset)
 
142
sec_to_TIME(MYSQL_TIME * tmp, my_time_t t, long offset)
139
143
{
140
144
  long days;
141
145
  long rem;
142
146
  int y;
143
147
  int yleap;
144
 
  const uint32_t *ip;
 
148
  const uint *ip;
145
149
 
146
150
  days= (long) (t / SECS_PER_DAY);
147
151
  rem=  (long) (t % SECS_PER_DAY);
191
195
  tmp->month++;
192
196
  tmp->day= (uint)(days + 1);
193
197
 
194
 
  /* filling MySQL specific DRIZZLE_TIME members */
 
198
  /* filling MySQL specific MYSQL_TIME members */
195
199
  tmp->neg= 0; tmp->second_part= 0;
196
 
  tmp->time_type= DRIZZLE_TIMESTAMP_DATETIME;
 
200
  tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
197
201
}
198
202
 
199
203
 
220
224
*/
221
225
static uint
222
226
find_time_range(my_time_t t, const my_time_t *range_boundaries,
223
 
                uint32_t higher_bound)
 
227
                uint higher_bound)
224
228
{
225
 
  uint32_t i, lower_bound= 0;
 
229
  uint i, lower_bound= 0;
226
230
 
227
231
  /*
228
232
    Function will work without this assertion but result would be meaningless.
283
287
 
284
288
/*
285
289
  Converts time in my_time_t representation (seconds in UTC since Epoch) to
286
 
  broken down DRIZZLE_TIME representation in local time zone.
 
290
  broken down MYSQL_TIME representation in local time zone.
287
291
 
288
292
  SYNOPSIS
289
293
    gmt_sec_to_TIME()
298
302
    (60th and 61st second, look how we calculate them as "hit" in this
299
303
    function).
300
304
    Under realistic assumptions about frequency of transitions the same array
301
 
    can be used fot DRIZZLE_TIME -> my_time_t conversion. For this we need to
 
305
    can be used fot MYSQL_TIME -> my_time_t conversion. For this we need to
302
306
    implement tweaked binary search which will take into account that some
303
 
    DRIZZLE_TIME has two matching my_time_t ranges and some of them have none.
 
307
    MYSQL_TIME has two matching my_time_t ranges and some of them have none.
304
308
*/
305
309
static void
306
 
gmt_sec_to_TIME(DRIZZLE_TIME *tmp, my_time_t sec_in_utc, const TIME_ZONE_INFO *sp)
 
310
gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t sec_in_utc, const TIME_ZONE_INFO *sp)
307
311
{
308
312
  const TRAN_TYPE_INFO *ttisp;
309
313
  const LS_INFO *lp;
405
409
}
406
410
 
407
411
/*
408
 
  Converts local time in broken down DRIZZLE_TIME representation to my_time_t
 
412
  Converts local time in broken down MYSQL_TIME representation to my_time_t
409
413
  representation.
410
414
 
411
415
  SYNOPSIS
447
451
 
448
452
    We use completely different approach. It is better since it is both
449
453
    faster than iterative implementations and fully determenistic. If you
450
 
    look at my_time_t to DRIZZLE_TIME conversion then you'll find that it consist
 
454
    look at my_time_t to MYSQL_TIME conversion then you'll find that it consist
451
455
    of two steps:
452
456
    The first is calculating shifted my_time_t value and the second - TIME
453
457
    calculation from shifted my_time_t value (well it is a bit simplified
477
481
    0 in case of error.
478
482
*/
479
483
static my_time_t
480
 
TIME_to_gmt_sec(const DRIZZLE_TIME *t, const TIME_ZONE_INFO *sp,
 
484
TIME_to_gmt_sec(const MYSQL_TIME *t, const TIME_ZONE_INFO *sp,
481
485
                bool *in_dst_time_gap)
482
486
{
483
487
  my_time_t local_t;
484
 
  uint32_t saved_seconds;
485
 
  uint32_t i;
 
488
  uint saved_seconds;
 
489
  uint i;
486
490
  int shift= 0;
487
491
 
488
492
  if (!validate_timestamp_range(t))
583
587
/*
584
588
  String with names of SYSTEM time zone.
585
589
*/
586
 
static const String tz_SYSTEM_name("SYSTEM", 6, &my_charset_utf8_general_ci);
 
590
static const String tz_SYSTEM_name("SYSTEM", 6, &my_charset_latin1);
587
591
 
588
592
 
589
593
/*
600
604
{
601
605
public:
602
606
  Time_zone_system() {}                       /* Remove gcc warning */
603
 
  virtual my_time_t TIME_to_gmt_sec(const DRIZZLE_TIME *t,
 
607
  virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
604
608
                                    bool *in_dst_time_gap) const;
605
 
  virtual void gmt_sec_to_TIME(DRIZZLE_TIME *tmp, my_time_t t) const;
 
609
  virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
606
610
  virtual const String * get_name() const;
607
611
};
608
612
 
609
613
 
610
614
/*
611
 
  Converts local time in system time zone in DRIZZLE_TIME representation
 
615
  Converts local time in system time zone in MYSQL_TIME representation
612
616
  to its my_time_t representation.
613
617
 
614
618
  SYNOPSIS
615
619
    TIME_to_gmt_sec()
616
 
      t               - pointer to DRIZZLE_TIME structure with local time in
 
620
      t               - pointer to MYSQL_TIME structure with local time in
617
621
                        broken-down representation.
618
622
      in_dst_time_gap - pointer to bool which is set to true if datetime
619
623
                        value passed doesn't really exist (i.e. falls into
621
625
 
622
626
  DESCRIPTION
623
627
    This method uses system function (localtime_r()) for conversion
624
 
    local time in system time zone in DRIZZLE_TIME structure to its my_time_t
 
628
    local time in system time zone in MYSQL_TIME structure to its my_time_t
625
629
    representation. Unlike the same function for Time_zone_db class
626
630
    it it won't handle unnormalized input properly. Still it will
627
631
    return lowest possible my_time_t in case of ambiguity or if we
633
637
    Corresponding my_time_t value or 0 in case of error
634
638
*/
635
639
my_time_t
636
 
Time_zone_system::TIME_to_gmt_sec(const DRIZZLE_TIME *t, bool *in_dst_time_gap) const
 
640
Time_zone_system::TIME_to_gmt_sec(const MYSQL_TIME *t, bool *in_dst_time_gap) const
637
641
{
638
642
  long not_used;
639
643
  return my_system_gmt_sec(t, &not_used, in_dst_time_gap);
646
650
 
647
651
  SYNOPSIS
648
652
    gmt_sec_to_TIME()
649
 
      tmp - pointer to DRIZZLE_TIME structure to fill-in
 
653
      tmp - pointer to MYSQL_TIME structure to fill-in
650
654
      t   - my_time_t value to be converted
651
655
 
652
656
  NOTE
657
661
    the 1902 easily.
658
662
*/
659
663
void
660
 
Time_zone_system::gmt_sec_to_TIME(DRIZZLE_TIME *tmp, my_time_t t) const
 
664
Time_zone_system::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
661
665
{
662
666
  struct tm tmp_tm;
663
667
  time_t tmp_t= (time_t)t;
664
668
 
665
669
  localtime_r(&tmp_t, &tmp_tm);
666
670
  localtime_to_TIME(tmp, &tmp_tm);
667
 
  tmp->time_type= DRIZZLE_TIMESTAMP_DATETIME;
 
671
  tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
668
672
}
669
673
 
670
674
 
687
691
/*
688
692
  Instance of this class represents UTC time zone. It uses system gmtime_r
689
693
  function for conversions and is always available. It is used only for
690
 
  my_time_t -> DRIZZLE_TIME conversions in various UTC_...  functions, it is not
691
 
  intended for DRIZZLE_TIME -> my_time_t conversions and shouldn't be exposed to user.
 
694
  my_time_t -> MYSQL_TIME conversions in various UTC_...  functions, it is not
 
695
  intended for MYSQL_TIME -> my_time_t conversions and shouldn't be exposed to user.
692
696
*/
693
697
class Time_zone_utc : public Time_zone
694
698
{
695
699
public:
696
700
  Time_zone_utc() {}                          /* Remove gcc warning */
697
 
  virtual my_time_t TIME_to_gmt_sec(const DRIZZLE_TIME *t,
 
701
  virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
698
702
                                    bool *in_dst_time_gap) const;
699
 
  virtual void gmt_sec_to_TIME(DRIZZLE_TIME *tmp, my_time_t t) const;
 
703
  virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
700
704
  virtual const String * get_name() const;
701
705
};
702
706
 
703
707
 
704
708
/*
705
 
  Convert UTC time from DRIZZLE_TIME representation to its my_time_t representation.
 
709
  Convert UTC time from MYSQL_TIME representation to its my_time_t representation.
706
710
 
707
711
  SYNOPSIS
708
712
    TIME_to_gmt_sec()
709
 
      t               - pointer to DRIZZLE_TIME structure with local time
 
713
      t               - pointer to MYSQL_TIME structure with local time
710
714
                        in broken-down representation.
711
715
      in_dst_time_gap - pointer to bool which is set to true if datetime
712
716
                        value passed doesn't really exist (i.e. falls into
721
725
    0
722
726
*/
723
727
my_time_t
724
 
Time_zone_utc::TIME_to_gmt_sec(const DRIZZLE_TIME *t __attribute__((unused)),
725
 
                               bool *in_dst_time_gap __attribute__((unused))) const
 
728
Time_zone_utc::TIME_to_gmt_sec(const MYSQL_TIME *t __attribute__((__unused__)),
 
729
                               bool *in_dst_time_gap __attribute__((__unused__))) const
726
730
{
727
731
  /* Should be never called */
728
732
  assert(0);
736
740
 
737
741
  SYNOPSIS
738
742
    gmt_sec_to_TIME()
739
 
      tmp - pointer to DRIZZLE_TIME structure to fill-in
 
743
      tmp - pointer to MYSQL_TIME structure to fill-in
740
744
      t   - my_time_t value to be converted
741
745
 
742
746
  NOTE
743
747
    See note for apropriate Time_zone_system method.
744
748
*/
745
749
void
746
 
Time_zone_utc::gmt_sec_to_TIME(DRIZZLE_TIME *tmp, my_time_t t) const
 
750
Time_zone_utc::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
747
751
{
748
752
  struct tm tmp_tm;
749
753
  time_t tmp_t= (time_t)t;
750
754
  gmtime_r(&tmp_t, &tmp_tm);
751
755
  localtime_to_TIME(tmp, &tmp_tm);
752
 
  tmp->time_type= DRIZZLE_TIMESTAMP_DATETIME;
 
756
  tmp->time_type= MYSQL_TIMESTAMP_DATETIME;
753
757
}
754
758
 
755
759
 
784
788
{
785
789
public:
786
790
  Time_zone_db(TIME_ZONE_INFO *tz_info_arg, const String * tz_name_arg);
787
 
  virtual my_time_t TIME_to_gmt_sec(const DRIZZLE_TIME *t,
 
791
  virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
788
792
                                    bool *in_dst_time_gap) const;
789
 
  virtual void gmt_sec_to_TIME(DRIZZLE_TIME *tmp, my_time_t t) const;
 
793
  virtual void gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
790
794
  virtual const String * get_name() const;
791
795
private:
792
796
  TIME_ZONE_INFO *tz_info;
820
824
 
821
825
  SYNOPSIS
822
826
    TIME_to_gmt_sec()
823
 
      t               - pointer to DRIZZLE_TIME structure with local time
 
827
      t               - pointer to MYSQL_TIME structure with local time
824
828
                        in broken-down representation.
825
829
      in_dst_time_gap - pointer to bool which is set to true if datetime
826
830
                        value passed doesn't really exist (i.e. falls into
834
838
    Corresponding my_time_t value or 0 in case of error
835
839
*/
836
840
my_time_t
837
 
Time_zone_db::TIME_to_gmt_sec(const DRIZZLE_TIME *t, bool *in_dst_time_gap) const
 
841
Time_zone_db::TIME_to_gmt_sec(const MYSQL_TIME *t, bool *in_dst_time_gap) const
838
842
{
839
843
  return ::TIME_to_gmt_sec(t, tz_info, in_dst_time_gap);
840
844
}
846
850
 
847
851
  SYNOPSIS
848
852
    gmt_sec_to_TIME()
849
 
      tmp - pointer to DRIZZLE_TIME structure to fill-in
 
853
      tmp - pointer to MYSQL_TIME structure to fill-in
850
854
      t   - my_time_t value to be converted
851
855
*/
852
856
void
853
 
Time_zone_db::gmt_sec_to_TIME(DRIZZLE_TIME *tmp, my_time_t t) const
 
857
Time_zone_db::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
854
858
{
855
859
  ::gmt_sec_to_TIME(tmp, t, tz_info);
856
860
}
880
884
{
881
885
public:
882
886
  Time_zone_offset(long tz_offset_arg);
883
 
  virtual my_time_t TIME_to_gmt_sec(const DRIZZLE_TIME *t,
 
887
  virtual my_time_t TIME_to_gmt_sec(const MYSQL_TIME *t,
884
888
                                    bool *in_dst_time_gap) const;
885
 
  virtual void   gmt_sec_to_TIME(DRIZZLE_TIME *tmp, my_time_t t) const;
 
889
  virtual void   gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const;
886
890
  virtual const String * get_name() const;
887
891
  /*
888
892
    This have to be public because we want to be able to access it from
907
911
Time_zone_offset::Time_zone_offset(long tz_offset_arg):
908
912
  offset(tz_offset_arg)
909
913
{
910
 
  uint32_t hours= abs((int)(offset / SECS_PER_HOUR));
911
 
  uint32_t minutes= abs((int)(offset % SECS_PER_HOUR / SECS_PER_MIN));
 
914
  uint hours= abs((int)(offset / SECS_PER_HOUR));
 
915
  uint minutes= abs((int)(offset % SECS_PER_HOUR / SECS_PER_MIN));
912
916
  ulong length= snprintf(name_buff, sizeof(name_buff), "%s%02d:%02d",
913
917
                         (offset>=0) ? "+" : "-", hours, minutes);
914
 
  name.set(name_buff, length, &my_charset_utf8_general_ci);
 
918
  name.set(name_buff, length, &my_charset_latin1);
915
919
}
916
920
 
917
921
 
918
922
/*
919
923
  Converts local time in time zone described as offset from UTC
920
 
  from DRIZZLE_TIME representation to its my_time_t representation.
 
924
  from MYSQL_TIME representation to its my_time_t representation.
921
925
 
922
926
  SYNOPSIS
923
927
    TIME_to_gmt_sec()
924
 
      t               - pointer to DRIZZLE_TIME structure with local time
 
928
      t               - pointer to MYSQL_TIME structure with local time
925
929
                        in broken-down representation.
926
930
      in_dst_time_gap - pointer to bool which should be set to true if
927
931
                        datetime  value passed doesn't really exist
933
937
    Corresponding my_time_t value or 0 in case of error
934
938
*/
935
939
my_time_t
936
 
Time_zone_offset::TIME_to_gmt_sec(const DRIZZLE_TIME *t,
937
 
                                  bool *in_dst_time_gap __attribute__((unused))) const
 
940
Time_zone_offset::TIME_to_gmt_sec(const MYSQL_TIME *t,
 
941
                                  bool *in_dst_time_gap __attribute__((__unused__))) const
938
942
{
939
943
  my_time_t local_t;
940
944
  int shift= 0;
979
983
 
980
984
  SYNOPSIS
981
985
    gmt_sec_to_TIME()
982
 
      tmp - pointer to DRIZZLE_TIME structure to fill-in
 
986
      tmp - pointer to MYSQL_TIME structure to fill-in
983
987
      t   - my_time_t value to be converted
984
988
*/
985
989
void
986
 
Time_zone_offset::gmt_sec_to_TIME(DRIZZLE_TIME *tmp, my_time_t t) const
 
990
Time_zone_offset::gmt_sec_to_TIME(MYSQL_TIME *tmp, my_time_t t) const
987
991
{
988
992
  sec_to_TIME(tmp, t, offset);
989
993
}
1048
1052
*/
1049
1053
bool
1050
1054
my_tz_init(THD *thd, const char *default_tzname,
1051
 
           bool bootstrap __attribute__((unused)))
 
1055
           bool bootstrap __attribute__((__unused__)))
1052
1056
{
1053
1057
  if (default_tzname)
1054
1058
  {
1055
 
    String tmp_tzname2(default_tzname, &my_charset_utf8_general_ci);
 
1059
    String tmp_tzname2(default_tzname, &my_charset_latin1);
1056
1060
    /*
1057
1061
      Time zone tables may be open here, and my_tz_find() may open
1058
1062
      most of them once more, but this is OK for system tables open
1060
1064
    */
1061
1065
    if (!(global_system_variables.time_zone= my_tz_find(thd, &tmp_tzname2)))
1062
1066
    {
1063
 
      sql_print_error(_("Fatal error: Illegal or unknown default time zone '%s'"),
 
1067
      sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
1064
1068
                      default_tzname);
1065
1069
      return true;
1066
1070
    }
1098
1102
    1 - String doesn't contain valid time zone offset
1099
1103
*/
1100
1104
bool
1101
 
str_to_offset(const char *str, uint32_t length, long *offset)
 
1105
str_to_offset(const char *str, uint length, long *offset)
1102
1106
{
1103
1107
  const char *end= str + length;
1104
1108
  bool negative;
1118
1122
 
1119
1123
  number_tmp= 0;
1120
1124
 
1121
 
  while (str < end && my_isdigit(&my_charset_utf8_general_ci, *str))
 
1125
  while (str < end && my_isdigit(&my_charset_latin1, *str))
1122
1126
  {
1123
1127
    number_tmp= number_tmp*10 + *str - '0';
1124
1128
    str++;
1130
1134
 
1131
1135
  offset_tmp = number_tmp * MINS_PER_HOUR; number_tmp= 0;
1132
1136
 
1133
 
  while (str < end && my_isdigit(&my_charset_utf8_general_ci, *str))
 
1137
  while (str < end && my_isdigit(&my_charset_latin1, *str))
1134
1138
  {
1135
1139
    number_tmp= number_tmp * 10 + *str - '0';
1136
1140
    str++;
1166
1170
 
1167
1171
*/
1168
1172
Time_zone *
1169
 
my_tz_find(THD *thd __attribute__((unused)),
1170
 
           const String *name __attribute__((unused)))
 
1173
my_tz_find(THD *thd __attribute__((__unused__)),
 
1174
           const String *name __attribute__((__unused__)))
1171
1175
{
1172
1176
  return NULL;
1173
1177
}