CUBRID Engine  latest
tz_support.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * tz_support.c : Timezone runtime support
21  */
22 
23 #include "config.h"
24 
25 #include <assert.h>
26 
27 #include "tz_support.h"
28 
29 #include "db_date.h"
30 #include "environment_variable.h"
31 #include "chartype.h"
32 #include "error_manager.h"
33 #if !defined(WINDOWS)
34 #include <dlfcn.h>
35 #include <unistd.h>
36 #endif
37 #include "system_parameter.h"
38 #include "show_scan.h"
39 #if defined (SERVER_MODE) || defined (SA_MODE)
40 #include "session.h"
41 #endif /* defined (SERVER_MODE) || defined (SA_MODE) */
42 #if !defined (SERVER_MODE)
43 #include "authenticate.h"
44 #include "db.h"
45 #endif /* !defined (SERVER_MODE) */
46 #include "boot_sr.h"
47 #include "dbtype.h"
48 #if defined (SERVER_MODE)
49 #include "thread_manager.hpp"
50 #endif // SERVER_MODE
51 
52 #if defined (SUPPRESS_STRLEN_WARNING)
53 #define strlen(s1) ((int) strlen(s1))
54 #endif /* defined (SUPPRESS_STRLEN_WARNING) */
55 
58 {
59  TZ_REGION_TYPE type; /* 0 : offset ; 1 : zone + DST */
60  union
61  {
62  int offset; /* in seconds */
63  struct
64  {
65  unsigned int zone_id; /* geographical zone id */
66  unsigned int offset_id; /* GMT offset rule id; MAX_INT if not yet determined */
67  unsigned int dst_id; /* daylight rule id ; MAX_INT if not yet determined */
69 
73  } zone;
74  };
75 };
76 
77 
79 {
80  FORWARD = 0,
82 };
84 
85 
86 #define FULL_DATE(jul_date, time_sec) ((full_date_t) jul_date * 86400ll \
87  + (full_date_t) time_sec)
88 #define TIME_OFFSET(is_utc, offset) \
89  ((is_utc) ? (-offset) : (offset))
90 #define ABS(i) ((i) >= 0 ? (i) : -(i))
91 
92 #define TZ_INVALID_OFFSET ((((23 * 60) + 59) * 60) + 59)
93 #define TZ_MIN_OFFSET -12 * 3600
94 #define TZ_MAX_OFFSET 14 * 3600
95 #define MILLIS_IN_A_DAY (long)(86400000) /* 24L * 60L * 60L * 1000 */
96 #define TZ_MASK_TZ_ID_FLAG 0xc0000000
97 #define TZ_BIT_SHIFT_TZ_ID_FLAG 30
98 #define TZ_OFFSET_MASK 0x3fffffff
99 #define SECONDS_IN_A_DAY 24 * 3600
100 
101 static int tz_Initialized = 0;
103 #if !defined(SERVER_MODE)
105 #endif
106 
107 /*
108  * structures and functions for loading timezone data
109  */
110 static void *tz_Lib_handle = NULL;
111 #if defined(WINDOWS)
112 static TZ_DATA
113  tz_Timezone_data = { 0, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, {'0'} };
114 
115 /* Timezone data generated when doing an extend */
116 static TZ_DATA
117  tz_New_timezone_data = { 0, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, {'0'} };
118 
119 #else
120 static TZ_DATA tz_Timezone_data = { 0, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, {'0'} };
121 
122 /* Timezone data generated when doing an extend */
123 static TZ_DATA tz_New_timezone_data = { 0, NULL, 0, NULL, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, {'0'} };
124 #endif
125 
126 static const int tz_Days_of_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
127 static const int tz_Days_up_to_month[] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
128 
129 #if defined (SA_MODE)
130 bool tz_Is_backward_compatible_timezone[ZONE_MAX];
131 bool tz_Compare_datetimetz_tz_id = false;
132 bool tz_Compare_timestamptz_tz_id = false;
133 #endif /* SA_MODE */
134 
135 static int tz_load_library (const char *lib_file, void **handle);
136 static int tz_load_data_from_lib (TZ_DATA * tzd, void *lib_handle);
137 static bool tz_get_leapsec_support (void);
138 static const TZ_REGION *tz_get_invalid_tz_region (void);
139 static DB_DATE tz_get_current_date (void);
140 static int tz_str_timezone_decode (const char *tz_str, const int tz_str_size, TZ_DECODE_INFO * tz_info,
141  const char **tz_end);
142 static int tz_zone_info_to_str (const TZ_DECODE_INFO * tz_info, char *tz_str, const int tz_str_size);
143 static void tz_encode_tz_id (const TZ_DECODE_INFO * tz_info, TZ_ID * tz_id);
144 static void tz_encode_tz_region (const TZ_DECODE_INFO * tz_info, TZ_REGION * tz_region);
145 static void tz_decode_tz_id (const TZ_ID * tz_id, const bool is_full_decode, TZ_DECODE_INFO * tz_info);
146 static void tz_decode_tz_region (const TZ_REGION * tz_region, TZ_DECODE_INFO * tz_info);
147 static int tz_fast_find_ds_rule (const TZ_DATA * tzd, const TZ_DS_RULESET * ds_ruleset, const int src_julian_date,
148  const int src_year, const int src_month, int *ds_rule_id);
149 static bool tz_check_ds_match_string (const TZ_OFFSET_RULE * off_rule, const TZ_DS_RULE * ds_rule,
150  const char *ds_string, const char *default_abrev);
151 static int tz_datetime_utc_conv (const DB_DATETIME * src_dt, TZ_DECODE_INFO * tz_info, bool src_is_utc,
152  bool only_tz_adjust, DB_DATETIME * dest_dt);
153 static int tz_conv_tz_datetime_w_zone_info (const DB_DATETIME * src_dt, const TZ_DECODE_INFO * src_zone_info_in,
154  const TZ_DECODE_INFO * dest_zone_info_in, DB_DATETIME * dest_dt,
155  TZ_DECODE_INFO * src_zone_info_out, TZ_DECODE_INFO * dest_zone_info_out);
156 static int tz_print_tz_offset (char *result, int tz_offset);
157 static int starts_with (const char *prefix, const char *str);
158 static int tz_get_zone_id_by_name (const char *name, const int name_size);
159 static void tz_timestamp_decode_leap_sec_adj (int timestamp, int *yearp, int *monthsp, int *dayp, int *hoursp,
160  int *minutesp, int *secondsp);
161 static int tz_offset (const bool src_is_utc, const TZ_TIME_TYPE until_time_type, const int gmt_offset_sec,
162  const int ds_save_time);
163 static int get_date_diff_from_ds_rule (const int src_julian_date, const int src_time_sec, const TZ_DS_RULE * ds_rule,
164  const DS_SEARCH_DIRECTION direction, full_date_t * date_diff);
165 static int get_closest_ds_rule (const int src_julian_date, const int src_time_sec, const TZ_DS_RULESET * ds_ruleset,
166  const TZ_DATA * tzd, const DS_SEARCH_DIRECTION direction);
167 static int get_saving_time_from_offset_rule (const TZ_OFFSET_RULE * offset_rule, const TZ_DATA * tzd, int *save_time);
168 static bool is_in_overlap_interval (const TZ_TIME_TYPE time_type, const full_date_t offset_rule_diff,
169  const full_date_t gmt_diff, const int save_time_diff);
170 static int get_year_to_apply_rule (const int src_year, const TZ_DS_RULE * ds_rule);
171 static int set_new_zone_id (TZ_DECODE_INFO * tz_info);
172 #if defined (LINUX)
173 static int find_timezone_from_clock (char *timezone_name, int buf_len);
174 static int find_timezone_from_localtime (char *timezone_name, int buf_len);
175 #endif
176 #if defined(WINDOWS)
177 static int tz_get_iana_zone_id_by_windows_zone (const char *windows_zone_name);
178 #endif
179 
180 #if defined(WINDOWS)
181 #define TZ_GET_SYM_ADDR(lib, sym) GetProcAddress((HMODULE)lib, sym)
182 #else
183 #define TZ_GET_SYM_ADDR(lib, sym) dlsym(lib, sym)
184 #endif
185 
186 #define TZLIB_GET_ADDR(v, SYM_NAME, SYM_TYPE, lh) \
187  do { \
188  v = (SYM_TYPE) TZ_GET_SYM_ADDR (lh, SYM_NAME); \
189  if (v == NULL) \
190  { \
191  strncpy (sym_name, (SYM_NAME), sizeof (sym_name) - 1); \
192  sym_name[sizeof (sym_name) - 1] = '\0'; \
193  goto error_loading_symbol; \
194  } \
195  } while (0)
196 
197 #define TZLIB_GET_VAL(v, SYM_NAME, SYM_TYPE, lh) \
198  do { \
199  SYM_TYPE* aux; \
200  TZLIB_GET_ADDR(aux, SYM_NAME, SYM_TYPE*, lh); \
201  v = *aux; \
202  } while (0)
203 
204 #define APPLY_NEXT_OFF_RULE() \
205  do { \
206  prev_off_rule = curr_off_rule; \
207  curr_off_rule = next_off_rule; \
208  next_off_rule = offset_rules[offset_rule_counter++]; \
209  curr_offset_id++; \
210  } while (0)
211 
212 /*
213  * tz_load_library - loads the timezone specific DLL/so
214  * Returns : error code - ER_LOC_INIT if library load fails
215  * - NO_ERROR if success
216  * lib_file(in) : path to library
217  * handle(out) : handle to the loaded library
218  */
219 static int
220 tz_load_library (const char *lib_file, void **handle)
221 {
222  int err_status = NO_ERROR;
223  char err_msg[512];
224 #if defined(WINDOWS)
225  DWORD loading_err;
226  char *lpMsgBuf;
227  UINT error_mode = 0;
228 #else
229  char *error;
230 #endif
231 
232  assert (lib_file != NULL);
233 
234 #if defined(WINDOWS)
235  error_mode = SetErrorMode (SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
236  *handle = LoadLibrary (lib_file);
237  SetErrorMode (error_mode);
238  loading_err = GetLastError ();
239 #elif defined(_AIX)
240  dlerror (); /* Clear any existing error */
241  *handle = dlopen (lib_file, RTLD_NOW | RTLD_MEMBER);
242 #else
243  dlerror (); /* Clear any existing error */
244  *handle = dlopen (lib_file, RTLD_NOW);
245 #endif
246 
247  if (*handle == NULL)
248  {
249  err_status = ER_TZ_LOAD_ERROR;
250  }
251 
252  if (err_status == ER_TZ_LOAD_ERROR)
253  {
254 #if defined(WINDOWS)
255  FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL,
256  loading_err, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (char *) &lpMsgBuf, 1,
257  (va_list *) & lib_file);
258  snprintf (err_msg, sizeof (err_msg) - 1,
259  "Library file is invalid or not accessible.\n" " Unable to load %s !\n %s", lib_file, lpMsgBuf);
260  LocalFree (lpMsgBuf);
261 #else
262  error = dlerror ();
263  snprintf_dots_truncate (err_msg, sizeof (err_msg) - 1,
264  "Library file is invalid or not accessible.\n" " Unable to load %s !\n %s", lib_file,
265  error);
266 #endif
267  printf ("%s\n", err_msg);
269  }
270 
271  return err_status;
272 }
273 
274 /*
275  * tz_load_data_from_lib() - uses the handle to load the data from the timezone shared library into tzd.
276  * Returns: 0 (NO_ERROR) if success, -1 otherwise
277  * tzd(out): TZ_DATA parameter where to load the data into
278  * lib_handle(in): shared library/object handle
279  */
280 static int
281 tz_load_data_from_lib (TZ_DATA * tzd, void *lib_handle)
282 {
283  char sym_name[TZLIB_SYMBOL_NAME_SIZE + 1];
284  char err_msg[512 + PATH_MAX];
285  char *checksum;
286 
287  assert (lib_handle != NULL);
288  assert (tzd != NULL);
289 
290  /* load data from the shared library */
291  TZLIB_GET_VAL (tzd->country_count, "tz_country_count", int, lib_handle);
292  TZLIB_GET_ADDR (tzd->countries, "tz_countries", TZ_COUNTRY *, lib_handle);
293 
294  TZLIB_GET_VAL (tzd->timezone_count, "timezone_count", int, lib_handle);
295  TZLIB_GET_ADDR (tzd->timezone_names, "tz_timezone_names", char **, lib_handle);
296  TZLIB_GET_ADDR (tzd->timezones, "timezones", TZ_TIMEZONE *, lib_handle);
297 
298  TZLIB_GET_VAL (tzd->offset_rule_count, "offset_rule_count", int, lib_handle);
299  TZLIB_GET_ADDR (tzd->offset_rules, "offset_rules", TZ_OFFSET_RULE *, lib_handle);
300 
301  TZLIB_GET_VAL (tzd->name_count, "tz_name_count", int, lib_handle);
302  TZLIB_GET_ADDR (tzd->names, "tz_names", TZ_NAME *, lib_handle);
303 
304  TZLIB_GET_VAL (tzd->ds_ruleset_count, "ds_ruleset_count", int, lib_handle);
305  TZLIB_GET_ADDR (tzd->ds_rulesets, "ds_rulesets", TZ_DS_RULESET *, lib_handle);
306 
307  TZLIB_GET_VAL (tzd->ds_rule_count, "ds_rule_count", int, lib_handle);
308  TZLIB_GET_ADDR (tzd->ds_rules, "ds_rules", TZ_DS_RULE *, lib_handle);
309 
310  TZLIB_GET_VAL (tzd->ds_leap_sec_count, "ds_leap_sec_count", int, lib_handle);
311  TZLIB_GET_ADDR (tzd->ds_leap_sec, "ds_leap_sec", TZ_LEAP_SEC *, lib_handle);
312 
313 #if defined(WINDOWS)
314  TZLIB_GET_VAL (tzd->windows_iana_map_count, "windows_iana_map_count", int, lib_handle);
315  TZLIB_GET_ADDR (tzd->windows_iana_map, "windows_iana_map", TZ_WINDOWS_IANA_MAP *, lib_handle);
316 #endif
317 
318  TZLIB_GET_ADDR (checksum, "tz_timezone_checksum", char *, lib_handle);
319  strncpy (tzd->checksum, checksum, 32);
320  tzd->checksum[32] = '\0';
321 
322  return NO_ERROR;
323 
324 error_loading_symbol:
325  snprintf (err_msg, sizeof (err_msg) - 1, "Cannot load symbol '%s' from the timezone library file!", sym_name);
326  printf ("%s\n", err_msg);
328 
329  return ER_TZ_LOAD_ERROR;
330 }
331 
332 /*
333  * tz_load() - opens the timezone library and loads the data into the tzd parameter
334  * Returns: 0 (NO_ERROR) if success, -1 otherwise
335  */
336 int
337 tz_load (void)
338 {
339  int err_status = NO_ERROR;
340  char lib_file[PATH_MAX] = { 0 };
341 
342  if (tz_Initialized)
343  {
344  return err_status;
345  }
346 
347  envvar_libdir_file (lib_file, PATH_MAX, LIB_TZ_NAME);
348  err_status = tz_load_library (lib_file, &tz_Lib_handle);
349 
350  if (err_status != NO_ERROR)
351  {
352  goto error_exit;
353  }
354 
355  err_status = tz_load_data_from_lib (&tz_Timezone_data, tz_Lib_handle);
356  if (err_status != NO_ERROR)
357  {
358  goto error_exit;
359  }
360 
361  tz_Initialized = 1;
362 
363  return NO_ERROR;
364 
365 error_exit:
366 
367  if (er_errid () == NO_ERROR)
368  {
369  err_status = ER_TZ_LOAD_ERROR;
371  }
372 
373  return err_status;
374 }
375 
376 /*
377  * tz_unload () - destroy all timezone related data
378  * Returns:
379  */
380 void
381 tz_unload (void)
382 {
383  memset (&tz_Timezone_data, 0, sizeof (tz_Timezone_data));
384 
385  if (tz_Lib_handle != NULL)
386  {
387 #if defined(WINDOWS)
388  FreeLibrary ((HMODULE) tz_Lib_handle);
389 #else
390  dlclose (tz_Lib_handle);
391 #endif
392  tz_Lib_handle = NULL;
393  }
394  tz_Initialized = 0;
395 }
396 
397 /*
398  * tz_get_leapsec_support() - returns true if leap-seconds
399  * are activated and false if not
400  */
401 static bool
403 {
404  bool leapsec_support;
405 
407 
408  return leapsec_support;
409 }
410 
411 /*
412  * tz_timestamp_encode_leap_sec_adj() - returns offset in seconds for leap second adjustment
413  */
414 DB_BIGINT
415 tz_timestamp_encode_leap_sec_adj (const int year_century, const int year, const int mon, const int day)
416 {
417  DB_BIGINT t = 0;
418  int len, index;
419  const TZ_DATA *tzd;
420  TZ_LEAP_SEC leap_second;
421 
422  tzd = tz_get_data ();
423 
424  if (tzd == NULL || tz_get_leapsec_support () == false)
425  {
426  return 0;
427  }
428 
429  len = tzd->ds_leap_sec_count;
430  index = 0;
431  while (index < len)
432  {
433  leap_second = tzd->ds_leap_sec[index];
434 
435  if (leap_second.year > year_century + year)
436  {
437  break;
438  }
439  if (leap_second.year == year_century + year)
440  {
441  if ((mon < leap_second.month) || (mon == leap_second.month && day <= leap_second.day))
442  {
443  break;
444  }
445  }
446  index++;
447  }
448  t = index;
449 
450  return t;
451 }
452 
453 /*
454  * tz_timestamp_decode_sec() - extracts from a UNIX timestamp the year, month, day, hour, minute and second
455  *
456  */
457 void
458 tz_timestamp_decode_sec (int timestamp, int *yearp, int *monthsp, int *dayp, int *hoursp, int *minutesp, int *secondsp)
459 {
460  if (tz_get_leapsec_support () == false)
461  {
462  tz_timestamp_decode_no_leap_sec (timestamp, yearp, monthsp, dayp, hoursp, minutesp, secondsp);
463  }
464  else
465  {
466  tz_timestamp_decode_leap_sec_adj (timestamp, yearp, monthsp, dayp, hoursp, minutesp, secondsp);
467  }
468 }
469 
470 /*
471  * tz_timestamp_decode_leap_sec_adj() - returns offset in seconds for leap second adjustment
472  */
473 static void
474 tz_timestamp_decode_leap_sec_adj (int timestamp, int *yearp, int *monthsp, int *dayp, int *hoursp, int *minutesp,
475  int *secondsp)
476 {
477  const int year_base = 1970;
478  const int secs_per_day = 24 * 3600;
479  int index, leap_cnt;
480  int leap, diff, i;
481  int year, months, day;
482  int hours, minutes, seconds;
483  const TZ_DATA *tzd;
484 
485  year = 0;
486  months = 0;
487 
488  tzd = tz_get_data ();
489  index = 0;
490 
491  if (tzd != NULL)
492  {
493  leap_cnt = tzd->ds_leap_sec_count;
494  }
495  else
496  {
497  leap_cnt = 0;
498  }
499 
500  /* get number of years */
501  for (;;)
502  {
503  int days_in_year;
504  leap = 0;
505 
506  if (IS_LEAP_YEAR (year_base + year))
507  {
508  days_in_year = 366;
509  }
510  else
511  {
512  days_in_year = 365;
513  }
514 
515  while (index < leap_cnt && tzd->ds_leap_sec[index].year == year_base + year)
516  {
517  index++;
518  leap++;
519  }
520 
521  if (timestamp - days_in_year * secs_per_day - leap < 0)
522  {
523  index -= leap;
524  break;
525  }
526 
527  timestamp -= days_in_year * secs_per_day + leap;
528  year++;
529  }
530 
531  /* Get the number of months */
532  for (i = TZ_MON_JAN; i <= TZ_MON_DEC; i++)
533  {
534  int subtract = tz_Days_of_month[i] * secs_per_day;
535  leap = 0;
536 
537  /* leap year and february */
538  if (IS_LEAP_YEAR (year_base + year) && i == TZ_MON_FEB)
539  {
540  subtract += secs_per_day;
541  }
542 
543  while (index < leap_cnt && tzd->ds_leap_sec[index].year == year_base + year
544  && tzd->ds_leap_sec[index].month == months)
545  {
546  index++;
547  leap++;
548  }
549 
550  if (timestamp - subtract - leap < 0)
551  {
552  index -= leap;
553  break;
554  }
555  timestamp -= subtract + leap;
556  months++;
557  }
558 
559  /* Get the number of days */
560  day = timestamp / secs_per_day;
561  timestamp = timestamp % secs_per_day;
562  leap = 0;
563 
564  while (index < leap_cnt && tzd->ds_leap_sec[index].year == year_base + year && tzd->ds_leap_sec[index].month == months
565  && tzd->ds_leap_sec[index].day <= day)
566  {
567  index++;
568  leap++;
569  }
570 
571  diff = timestamp - leap;
572  if (diff < 0)
573  {
574  day--;
575  timestamp = secs_per_day + diff;
576  }
577  else
578  {
579  timestamp = diff;
580  }
581  day++;
582 
583  /* Get the hours, minutes and seconds */
584  hours = timestamp / 3600;
585  minutes = (timestamp % 3600) / 60;
586  seconds = (timestamp % 3600) % 60;
587 
588  *yearp = year + year_base;
589  *monthsp = months;
590  *dayp = day;
591  *hoursp = hours;
592  *minutesp = minutes;
593  *secondsp = seconds;
594 }
595 
596 /*
597  * tz_timestamp_decode_no_leap_sec() - extracts from a UNIX timestamp the year, month, day, hour, minute
598  * and second without taking into account leap seconds
599  */
600 void
601 tz_timestamp_decode_no_leap_sec (int timestamp, int *yearp, int *monthsp, int *dayp, int *hoursp, int *minutesp,
602  int *secondsp)
603 {
604  const int year_base = 1970;
605  const int secs_per_day = 24 * 3600;
606  const int days_in_year = 365;
607  const int secs_in_a_year = secs_per_day * days_in_year;
608  int year, month, day;
609  int hours, minutes, seconds;
610  int secs_until_last_year;
611  int secs_until_last_month = 0;
612  int days_last_month;
613 
614  /* Get approximate number of years */
615  year = timestamp / (days_in_year * secs_per_day);
616  secs_until_last_year =
617  year * secs_in_a_year + ((year + 1) / 4) * secs_per_day - ((year + 69) / 100) * secs_per_day +
618  ((year + 369) / 400) * secs_per_day;
619 
620  /* If we overestimated the number of years take back one year */
621  if (timestamp - secs_until_last_year < 0)
622  {
623  year--;
624  secs_until_last_year -= secs_in_a_year;
625  if (IS_LEAP_YEAR (year_base + year))
626  {
627  secs_until_last_year -= secs_per_day;
628  }
629  }
630  timestamp -= secs_until_last_year;
631 
632  /* Get approximate number of months */
633  month = timestamp / (31 * secs_per_day);
634 
635  /* If we underestimated the number of months add another one */
636  if (month > TZ_MON_JAN)
637  {
638  secs_until_last_month = tz_Days_up_to_month[month - 1] * secs_per_day;
639  if (IS_LEAP_YEAR (year_base + year) && month > TZ_MON_FEB)
640  {
641  secs_until_last_month += secs_per_day;
642  }
643  }
644 
645  days_last_month = tz_Days_of_month[month] * secs_per_day;
646  if (IS_LEAP_YEAR (year_base + year) && month == TZ_MON_FEB)
647  {
648  days_last_month += secs_per_day;
649  }
650 
651  if (timestamp - secs_until_last_month - days_last_month >= 0)
652  {
653  secs_until_last_month += days_last_month;
654  month++;
655  }
656 
657  timestamp -= secs_until_last_month;
658 
659  /* Get the number of days */
660  day = timestamp / secs_per_day;
661  day++;
662  timestamp = timestamp % secs_per_day;
663 
664  /* Get the hours, minutes and seconds */
665  hours = timestamp / 3600;
666  minutes = (timestamp % 3600) / 60;
667  seconds = (timestamp % 3600) % 60;
668 
669  *yearp = year + year_base;
670  *monthsp = month;
671  *dayp = day;
672  *hoursp = hours;
673  *minutesp = minutes;
674  *secondsp = seconds;
675 }
676 
677 /*
678  * Timezone CUBRID access functions
679  */
680 
681 /*
682  * tz_get_data() - get a reference to the global timezone data
683  *
684  * Returns: NULL if timezone data is not loaded, reference to it otherwise
685  */
686 const TZ_DATA *
688 {
689  if (tz_Timezone_data.timezone_count == 0)
690  {
691  return NULL;
692  }
693 
694  return &tz_Timezone_data;
695 }
696 
697 /*
698  * tz_set_data() - Set the new timezone data
699  * Returns: void
700  */
701 void
702 tz_set_data (const TZ_DATA * data)
703 {
704  tz_Timezone_data = *data;
705 }
706 
707 /*
708  * tz_get_new_data() - get a reference to the global new timezone data
709  *
710  * Returns: NULL if timezone data is not loaded, reference to it otherwise
711  */
712 const TZ_DATA *
714 {
715  if (tz_New_timezone_data.timezone_count == 0)
716  {
717  return NULL;
718  }
719 
720  return &tz_New_timezone_data;
721 }
722 
723 /*
724  * tz_set_new_timezone_data() - Set the new timezone data
725  *
726  * Returns: void
727  */
728 void
730 {
731  tz_New_timezone_data = *data;
732 }
733 
734 /*
735  * tz_get_session_local_timezone - returns session timezone
736  *
737  */
738 const char *
740 {
742 }
743 
744 /*
745  * tz_get_system_timezone - returns server timezone
746  *
747  */
748 const char *
750 {
752 }
753 
754 /*
755  * tz_get_system_tz_region() - get the system timezone region
756  */
757 void
759 {
760  *tz_region = tz_Region_system;
761 }
762 
763 /*
764  * tz_get_session_tz_region() - get the session timezone region
765  */
766 void
768 {
769  TZ_REGION *session_tz_region;
770 
771 #if defined(CS_MODE)
772  session_tz_region = tz_get_client_tz_region_session ();
773  *tz_region = *session_tz_region;
774 #else /* SERVER or SA_MODE */
775  if (BO_IS_SERVER_RESTARTED ())
776  {
777 #if defined(SERVER_MODE)
778  session_tz_region = tz_get_server_tz_region_session ();
779 #else
780  session_tz_region = tz_get_client_tz_region_session ();
781 #endif /* SERVER_MODE */
782  if (session_tz_region != NULL)
783  {
784  *tz_region = *session_tz_region;
785  }
786  else
787  {
788  /* A session could not be found with this thread, use invalid region */
789  *tz_region = *tz_get_invalid_tz_region ();
790  }
791  }
792  else
793  {
794  *tz_region = tz_Region_system;
795  }
796 #endif /* CS_MODE */
797 }
798 
799 /*
800  * tz_id_to_region() - converts a TZ_ID into a TZ_REGION
801  */
802 void
803 tz_id_to_region (const TZ_ID * tz_id, TZ_REGION * tz_region)
804 {
805  TZ_DECODE_INFO tz_info;
806 
807  tz_decode_tz_id (tz_id, false, &tz_info);
808  tz_encode_tz_region (&tz_info, tz_region);
809 }
810 
811 /*
812  * tz_get_utc_tz_id() - returns the compressed timezone identifer for UTC
813  *
814  */
815 const TZ_ID *
817 {
818  static const TZ_ID utc_tz_id = 0x1 << 30;
819 
820  return &utc_tz_id;
821 }
822 
823 /*
824  * tz_get_utc_tz_region() - return the timezone region for UTC
825  *
826  */
827 const TZ_REGION *
829 {
830  static const TZ_REGION utc_region = { TZ_REGION_OFFSET, {0} };
831 
832  return &utc_region;
833 }
834 
835 /*
836  * tz_get_invalid_tz_region() - returns the generic invalid timezone region
837  *
838  */
839 static const TZ_REGION *
841 {
842  static const TZ_REGION invalid_region = { TZ_REGION_OFFSET, {TZ_INVALID_OFFSET} };
843 
844  return &invalid_region;
845 }
846 
847 /*
848  * tz_get_current_date() -
849  *
850  */
851 static DB_DATE
853 {
854  DB_DATETIME datetime;
855  time_t time_val;
856  struct tm c_time_struct, *c_time_struct_p;
857 
858  time_val = time (NULL);
859  c_time_struct_p = localtime_r (&time_val, &c_time_struct);
860  if (c_time_struct_p == NULL)
861  {
862  db_datetime_encode (&datetime, 1, 1, 2012, 10, 30, 0, 0);
863  }
864  else
865  {
866  db_datetime_encode (&datetime, c_time_struct_p->tm_mon + 1, c_time_struct_p->tm_mday,
867  c_time_struct_p->tm_year + 1900, c_time_struct_p->tm_hour, c_time_struct_p->tm_min,
868  c_time_struct_p->tm_sec, 0);
869  }
870 
871  return datetime.date;
872 }
873 
874 /*
875  * tz_print_tz_offset () - stores in result in the format hh:mm or hh:mm:ss the number of seconds in tz_offset,
876  * where hh is the number of hours, mm the number of minutes and ss is the number of seconds
877  * hh:mm:ss format is used only if the number of seconds is positive
878  *
879  * tz_offset (in) : timezone offset represented in seconds
880  * result (out) : output timezone offset
881  */
882 
883 static int
884 tz_print_tz_offset (char *result, int tz_offset)
885 {
886  const int sign_hour_minutes = 6;
887  const int seconds = 3;
888  int off_hour, off_min, off_sec, out_len = 0;
889  char sign = '+';
890 
891  if (tz_offset < 0)
892  {
893  sign = '-';
894  tz_offset = -tz_offset;
895  }
896 
897  off_hour = tz_offset / 3600;
898  off_min = (tz_offset % 3600) / 60;
899  off_sec = (tz_offset % 3600) % 60;
900 
901  out_len += sign_hour_minutes;
902  if (off_sec != 0)
903  {
904  out_len += seconds;
905  }
906 
907  if (!off_sec)
908  {
909  if (snprintf (result, out_len + 1, "%c%02d:%02d", sign, off_hour, off_min) < 0)
910  {
911  assert (false);
912  return ER_FAILED;
913  }
914  }
915  else
916  {
917  if (snprintf (result, out_len + 1, "%c%02d:%02d:%02d", sign, off_hour, off_min, off_sec) < 0)
918  {
919  assert (false);
920  return ER_FAILED;
921  }
922  }
923  (result)[out_len] = '\0';
924  return NO_ERROR;
925 }
926 
927 /*
928  * tz_get_timezone_offset () - puts in result the timezone offset of tz_str timezone
929  * tz_str (in) : name or offset of timezone
930  * tz_size (in) : length of timezone string
931  * utc_datetime (in) : the current UTC datetime
932  * result (out) : the timezone offset
933  */
934 int
935 tz_get_timezone_offset (const char *tz_str, int tz_size, char *result, DB_DATETIME * utc_datetime)
936 {
937  const char *p = tz_str;
938  int error = NO_ERROR;
939 
940  while (p < tz_str + tz_size && char_isspace (*p))
941  {
942  p++;
943  }
944 
945  if (p >= tz_str + tz_size)
946  {
948  return ER_TZ_INVALID_TIMEZONE;
949  }
950 
951  if (*p == '+' || *p == '-')
952  {
953  int seconds = 0;
954  const char *zone_end;
955  if (tz_str_to_seconds (p, tz_str + tz_size, &seconds, &zone_end, true) != NO_ERROR)
956  {
958  return ER_TZ_INVALID_TIMEZONE;
959  }
960 
961  while (zone_end < tz_str + tz_size && char_isspace (*zone_end))
962  {
963  zone_end++;
964  }
965 
966  if (zone_end != tz_str + tz_size)
967  {
969  return ER_TZ_INVALID_TIMEZONE;
970  }
971 
972  error = tz_print_tz_offset (result, seconds);
973  }
974  /* Handle the main case when the timezone is a name */
975  else
976  {
977  int zone_id;
978  TZ_DECODE_INFO tzinfo;
979  DB_DATETIME dest_datetime;
980  int tdif;
981  const char *save_poz;
982  const char *end;
983 
984  save_poz = p;
985  while (p < tz_str + tz_size && !char_isspace (*p))
986  {
987  p++;
988  }
989  end = p;
990 
991  while (end < tz_str + tz_size && char_isspace (*end))
992  {
993  end++;
994  }
995  if (end != tz_str + tz_size)
996  {
998  return ER_TZ_INVALID_TIMEZONE;
999  }
1000 
1001  zone_id = tz_get_zone_id_by_name (save_poz, CAST_BUFLEN (p - save_poz));
1002  if (zone_id == -1)
1003  {
1005  return ER_TZ_INVALID_TIMEZONE;
1006  }
1007 
1008  tzinfo.type = TZ_REGION_ZONE;
1009  tzinfo.zone.zone_id = zone_id;
1010  tzinfo.zone.dst_str[0] = '\0';
1011 
1012  error = tz_datetime_utc_conv (utc_datetime, &tzinfo, true, false, &dest_datetime);
1013  if (error != NO_ERROR)
1014  {
1015  return error;
1016  }
1017 
1018  tdif =
1019  (int) (dest_datetime.date - utc_datetime->date) * 3600 * 24 + (int) (dest_datetime.time -
1020  utc_datetime->time) / 1000;
1021 
1022  error = tz_print_tz_offset (result, tdif);
1023  }
1024 
1025  return error;
1026 }
1027 
1028 /*
1029  * tz_create_session_tzid_for_datetime() - Creates a TZ_ID object for a DATETIME
1030  *
1031  * Returns: error code
1032  * src_dt(in): DATETIME value
1033  * src_is_utc(in): if true, than source DATETIME is considered in UTC, otherwise in in session timezone
1034  * tz_id(out): result TZ_ID
1035  */
1036 int
1037 tz_create_session_tzid_for_datetime (const DB_DATETIME * src_dt, bool src_is_utc, TZ_ID * tz_id)
1038 {
1039  TZ_DECODE_INFO tz_info;
1040  int er_status = NO_ERROR;
1041  DB_DATETIME dummy_dt;
1042  TZ_REGION session_tz_region;
1043 
1044  tz_get_session_tz_region (&session_tz_region);
1045  tz_decode_tz_region (&session_tz_region, &tz_info);
1046 
1047  /* we use tz_info which only has zone_id valid to establish correct offset and dst_id according to dt value */
1048  er_status = tz_datetime_utc_conv (src_dt, &tz_info, src_is_utc, true, &dummy_dt);
1049  if (er_status != NO_ERROR)
1050  {
1051  return er_status;
1052  }
1053 
1054  tz_encode_tz_id (&tz_info, tz_id);
1055 
1056  return er_status;
1057 }
1058 
1059 /*
1060  * tz_create_session_tzid_for_timestamp() - Creates a TZ_ID object for a TIMESTAMP
1061  *
1062  * Returns: error code
1063  * src_ts(in): TIMESTAMP value
1064  * tz_id(out): result TZ_ID
1065  *
1066  */
1067 int
1069 {
1070  DB_DATE date;
1071  DB_TIME time;
1072  DB_DATETIME dt;
1073 
1074  db_timestamp_decode_utc (src_ts, &date, &time);
1075  dt.date = date;
1076  dt.time = time * 1000;
1077 
1078  return tz_create_session_tzid_for_datetime (&dt, true, tz_id);
1079 }
1080 
1081 /*
1082  * tz_create_session_tzid_for_time() - Creates a TZ_ID object for a TIME
1083  *
1084  * Returns: error code
1085  * src_dt(in): TIME value
1086  * src_is_utc(in): if true, than source TIME is considered in UTC, otherwise in in session timezone
1087  * tz_id(out): result TZ_ID
1088  *
1089  */
1090 int
1091 tz_create_session_tzid_for_time (const DB_TIME * src_time, bool src_is_utc, TZ_ID * tz_id)
1092 {
1093  DB_DATETIME src_dt;
1094 
1095  src_dt.date = tz_get_current_date ();
1096  src_dt.time = *src_time;
1097 
1098  return tz_create_session_tzid_for_datetime (&src_dt, src_is_utc, tz_id);
1099 }
1100 
1101 /*
1102  * tz_get_zone_id_by_name() - returns the ID of a timezone having the specified name or alias.
1103  *
1104  * Returns: ID of zone, or -1 if not found
1105  * name(in): timezone name or alias to search for (not null-terminated)
1106  * name_size(in): size in bytes of name
1107  */
1108 static int
1109 tz_get_zone_id_by_name (const char *name, const int name_size)
1110 {
1111  const TZ_DATA *tzd;
1112  int name_index = -1;
1113  int index_bot, index_top;
1114  int cmp_res;
1115 
1116  assert (name != NULL);
1117 
1118  tzd = tz_get_data ();
1119  if (tzd == NULL)
1120  {
1121  return -1;
1122  }
1123 
1124  index_bot = 0;
1125  index_top = tzd->name_count - 1;
1126 
1127  while (index_bot <= index_top)
1128  {
1129  name_index = (index_bot + index_top) >> 1;
1130  cmp_res = strncmp (name, tzd->names[name_index].name, name_size);
1131 
1132  if (cmp_res < 0)
1133  {
1134  index_top = name_index - 1;
1135  }
1136  else if (cmp_res > 0)
1137  {
1138  index_bot = name_index + 1;
1139  }
1140  else
1141  {
1142  if (strlen (tzd->names[name_index].name) != name_size)
1143  {
1144  index_top = name_index - 1;
1145  continue;
1146  }
1147  return name_index;
1148  }
1149  }
1150 
1151  return -1;
1152 }
1153 
1154 /*
1155  * tz_str_timezone_decode () -
1156  *
1157  * Return: error code
1158  * tz_str(in): string containing timezone information (zone, daylight saving); not null-terminated
1159  * tz_str(in): string containing timezone information (zone, daylight saving); null-terminated
1160  * tz_info(out): object containing decoded timezone info
1161  * tz_end(out): pointer to end of zone information
1162  *
1163  * Valid formats for timezone string (leading/trailing whitespaces and
1164  * leading zeros are optional) :
1165  * - " +08:00 "
1166  * - " Europe/Berlin "
1167  * - " Europe/Berlin +08:00 "
1168  */
1169 static int
1170 tz_str_timezone_decode (const char *tz_str, const int tz_str_size, TZ_DECODE_INFO * tz_info, const char **tz_end)
1171 {
1172  const char *zone_str, *tz_str_end;
1173  const char *zone_str_end;
1174  int zone_id;
1175 
1176  tz_str_end = tz_str + tz_str_size;
1177 
1178  zone_str = tz_str;
1179  while (zone_str < tz_str_end && char_isspace (*zone_str))
1180  {
1181  zone_str++;
1182  }
1183 
1184  if (zone_str >= tz_str_end)
1185  {
1187  return ER_TZ_INVALID_TIMEZONE;
1188  }
1189 
1190  if (*zone_str == '+' || *zone_str == '-')
1191  {
1192  if (tz_str_to_seconds (zone_str, tz_str_end, &(tz_info->offset), &zone_str_end, true) != NO_ERROR)
1193  {
1195  return ER_TZ_INVALID_TIMEZONE;
1196  }
1197  tz_info->type = TZ_REGION_OFFSET;
1198  }
1199  else
1200  {
1201  const char *dst_str = NULL, *dst_str_end = NULL, *reg_str_end = NULL;
1202  /* zone plus optional DST */
1203  reg_str_end = zone_str;
1204  while (reg_str_end < tz_str_end && !char_isspace (*reg_str_end))
1205  {
1206  reg_str_end++;
1207  }
1208 
1209  dst_str = reg_str_end;
1210  while (dst_str < tz_str_end && char_isspace (*dst_str))
1211  {
1212  dst_str++;
1213  }
1214 
1215  if (dst_str < tz_str_end)
1216  {
1217  dst_str_end = dst_str;
1218  while (dst_str_end < tz_str_end && !char_isspace (*dst_str_end))
1219  {
1220  dst_str_end++;
1221  }
1222  zone_str_end = dst_str_end;
1223  }
1224  else
1225  {
1226  zone_str_end = dst_str;
1227  dst_str = NULL;
1228  }
1229 
1230  zone_id = tz_get_zone_id_by_name (zone_str, CAST_BUFLEN (reg_str_end - zone_str));
1231  if (zone_id == -1)
1232  {
1234  return ER_TZ_INVALID_TIMEZONE;
1235  }
1236 
1237  tz_info->type = TZ_REGION_ZONE;
1238  tz_info->zone.zone_id = zone_id;
1239  tz_info->zone.dst_id = TZ_DS_ID_MAX;
1240  tz_info->zone.offset_id = TZ_OFFSET_ID_MAX;
1241 
1242  if (dst_str != NULL)
1243  {
1244  if (dst_str_end - dst_str > (int) sizeof (tz_info->zone.dst_str))
1245  {
1247  return ER_TZ_INVALID_TIMEZONE;
1248  }
1249 
1250  strncpy (tz_info->zone.dst_str, dst_str, dst_str_end - dst_str);
1251  tz_info->zone.dst_str[dst_str_end - dst_str] = '\0';
1252  zone_str = dst_str_end;
1253  }
1254  else
1255  {
1256  tz_info->zone.dst_str[0] = '\0';
1257  }
1258  }
1259 
1260  if (tz_end != NULL)
1261  {
1262  while (zone_str_end < tz_str_end && char_isspace (*zone_str_end))
1263  {
1264  zone_str_end++;
1265  }
1266  *tz_end = zone_str_end;
1267  }
1268 
1269  return NO_ERROR;
1270 }
1271 
1272 /*
1273  * tz_str_to_region ()
1274  *
1275  * Return: error code
1276  * tz_str(in): string containing timezone information (zone, daylight saving); not null-terminated
1277  * tz_str_size(in): size in characters of zone information of tz_str
1278  * tz_region(out): object containing timezone info
1279  *
1280  * Valid formats for timezone string (leading/trailing white-spaces and leading zeros are optional) :
1281  * - " +08:00 "
1282  * - " Europe/Berlin "
1283  * - " Europe/Berlin +08:00 "
1284  */
1285 int
1286 tz_str_to_region (const char *tz_str, const int tz_str_size, TZ_REGION * tz_region)
1287 {
1288  const char *zone_str, *tz_str_end;
1289  const char *zone_str_end;
1290  int reg_zone_id, reg_offset;
1291  TZ_REGION_TYPE reg_type;
1292 
1293  tz_str_end = tz_str + tz_str_size;
1294  zone_str = tz_str;
1295 
1296  while (zone_str < tz_str_end && char_isspace (*zone_str))
1297  {
1298  zone_str++;
1299  }
1300 
1301  if (zone_str >= tz_str_end)
1302  {
1304  return ER_TZ_INVALID_TIMEZONE;
1305  }
1306 
1307  if (*zone_str == '+' || *zone_str == '-')
1308  {
1309  if (tz_str_to_seconds (zone_str, tz_str_end, &reg_offset, &zone_str_end, true) != NO_ERROR)
1310  {
1312  return ER_TZ_INVALID_TIMEZONE;
1313  }
1314 
1315  while (zone_str_end < tz_str_end && char_isspace (*zone_str_end))
1316  {
1317  zone_str_end++;
1318  }
1319 
1320  if (zone_str_end != tz_str_end)
1321  {
1323  return ER_TZ_INVALID_TIMEZONE;
1324  }
1325 
1326  reg_type = TZ_REGION_OFFSET;
1327  }
1328  else
1329  {
1330  const char *reg_str_end;
1331 
1332  reg_str_end = zone_str;
1333  while (reg_str_end < tz_str_end && !char_isspace (*reg_str_end))
1334  {
1335  reg_str_end++;
1336  }
1337 
1338  reg_zone_id = tz_get_zone_id_by_name (zone_str, CAST_BUFLEN (reg_str_end - zone_str));
1339  if (reg_zone_id == -1)
1340  {
1342  return ER_TZ_INVALID_TIMEZONE;
1343  }
1344 
1345  reg_type = TZ_REGION_ZONE;
1346  }
1347 
1348  if (tz_region != NULL)
1349  {
1350  tz_region->type = reg_type;
1351  if (reg_type == TZ_REGION_OFFSET)
1352  {
1353  tz_region->offset = reg_offset;
1354  }
1355  else
1356  {
1357  tz_region->zone_id = reg_zone_id;
1358  }
1359  }
1360 
1361  return NO_ERROR;
1362 }
1363 
1364 /*
1365  * tz_create_datetimetz () - transforms a DATETIME and timezone string (or default timezone identifier) into a DATETIME
1366  * (in UTC) with timezone info, considering the source DATETIME in specified timezone
1367  *
1368  * Return: error code
1369  * dt(in): decoded local datetime value (as appears in the user string)
1370  * tz_str(in): string containing timezone information (zone, daylight saving);
1371  * null-terminated, can be NULL, in which case default_tz_region is used
1372  * tz_size(in): size of tz_str
1373  * default_tz_region(in): default timezone region to apply if input string does not contain a valid zone information
1374  * dt_tz(out): object containing datetime value (adjusted to UTC) and timezone info
1375  * end_tz_str(out): pointer to end of parsed string
1376  *
1377  * Valid formats for timezone string (leading/trailing white-spaces and leading zero are optional) :
1378  * - " +08:00 "
1379  * - " Europe/Berlin "
1380  * - " Europe/Berlin +08:00 "
1381  */
1382 int
1383 tz_create_datetimetz (const DB_DATETIME * dt, const char *tz_str, const int tz_size,
1384  const TZ_REGION * default_tz_region, DB_DATETIMETZ * dt_tz, const char **end_tz_str)
1385 {
1386  int err_status = NO_ERROR;
1387  DB_DATETIME utc_dt;
1388  TZ_DECODE_INFO tz_info;
1389 
1390  if (end_tz_str != NULL)
1391  {
1392  *end_tz_str = NULL;
1393  }
1394 
1395  if (tz_str != NULL)
1396  {
1397  err_status = tz_str_timezone_decode (tz_str, tz_size, &tz_info, end_tz_str);
1398  if (err_status != NO_ERROR)
1399  {
1400  goto exit;
1401  }
1402  }
1403  else
1404  {
1405  tz_decode_tz_region (default_tz_region, &tz_info);
1406  }
1407 
1408  err_status = tz_datetime_utc_conv (dt, &tz_info, false, false, &utc_dt);
1409  if (err_status != NO_ERROR)
1410  {
1411  goto exit;
1412  }
1413  tz_encode_tz_id (&tz_info, &(dt_tz->tz_id));
1414  dt_tz->datetime = utc_dt;
1415 
1416 exit:
1417  return err_status;
1418 }
1419 
1420 /*
1421  * tz_create_timestamptz () - creates a timestamp with timezone from date and time values considering the user timezone
1422  * from tz_str; if this is NULL, then default_tz_region is used
1423  *
1424  * Return: error code
1425  * date(in): local date
1426  * time(in): local time
1427  * tz_str(in): string containing timezone information (zone, daylight saving);
1428  * null-terminated, can be NULL, in which case default_tz_region is used
1429  * tz_size(in): size of tz_str
1430  * default_tz_region(in): default timezone region to apply if input string does not contain a valid zone information
1431  * ts_tz(out): object containing timestamp value and timezone info
1432  *
1433  */
1434 int
1435 tz_create_timestamptz (const DB_DATE * date, const DB_TIME * time, const char *tz_str, const int tz_size,
1436  const TZ_REGION * default_tz_region, DB_TIMESTAMPTZ * ts_tz, const char **end_tz_str)
1437 {
1438  int err_status = NO_ERROR;
1439  DB_DATETIME utc_dt, dt;
1440  TZ_DECODE_INFO tz_info;
1441  DB_DATE date_utc;
1442  DB_TIME time_utc;
1443 
1444  if (end_tz_str != NULL)
1445  {
1446  *end_tz_str = NULL;
1447  }
1448 
1449  if (tz_str != NULL)
1450  {
1451  err_status = tz_str_timezone_decode (tz_str, tz_size, &tz_info, end_tz_str);
1452  if (err_status != NO_ERROR)
1453  {
1454  goto exit;
1455  }
1456  }
1457  else
1458  {
1459  tz_decode_tz_region (default_tz_region, &tz_info);
1460  }
1461 
1462  dt.date = *date;
1463  dt.time = (*time) * 1000;
1464 
1465  err_status = tz_datetime_utc_conv (&dt, &tz_info, false, false, &utc_dt);
1466  if (err_status != NO_ERROR)
1467  {
1468  goto exit;
1469  }
1470  date_utc = utc_dt.date;
1471  time_utc = utc_dt.time / 1000;
1472 
1473  err_status = db_timestamp_encode_utc (&date_utc, &time_utc, &ts_tz->timestamp);
1474  if (err_status != NO_ERROR)
1475  {
1476  goto exit;
1477  }
1478  tz_encode_tz_id (&tz_info, &(ts_tz->tz_id));
1479 
1480 exit:
1481  return err_status;
1482 }
1483 
1484 /*
1485  * tz_create_datetimetz_from_ses () - creates a datetime with timezone from a datetime using session timezone
1486  *
1487  * Return: error code
1488  * dt(in): decoded local datetime value (as appears in the user string)
1489  * dt_tz(out): object containing datetime value (adjusted to UTC) and timezone info
1490  *
1491  */
1492 int
1494 {
1495  int err_status = NO_ERROR;
1496  DB_DATETIME utc_dt;
1497  TZ_DECODE_INFO tz_info;
1498  TZ_REGION session_tz_region;
1499 
1500  tz_get_session_tz_region (&session_tz_region);
1501  tz_decode_tz_region (&session_tz_region, &tz_info);
1502 
1503  err_status = tz_datetime_utc_conv (dt, &tz_info, false, false, &utc_dt);
1504  if (err_status != NO_ERROR)
1505  {
1506  goto exit;
1507  }
1508  tz_encode_tz_id (&tz_info, &(dt_tz->tz_id));
1509  dt_tz->datetime = utc_dt;
1510 
1511 exit:
1512  return err_status;
1513 }
1514 
1515 /*
1516  * tz_conv_tz_time_w_zone_name() - Converts the time_source from timezone source zone into timezone dest_zone
1517  *
1518  *
1519  * Return: error code
1520  * time_source(in): object containing source time value
1521  * source_zone(in): source timezone string
1522  * len_source(in): length of source timezone string
1523  * dest_zone(in): destination timezone string
1524  * len_dest(in): length of destination timezone string
1525  * time_dest(out): object containing output time value
1526  */
1527 int
1528 tz_conv_tz_time_w_zone_name (const DB_TIME * time_source, const char *source_zone, int len_source,
1529  const char *dest_zone, int len_dest, DB_TIME * time_dest)
1530 {
1531  int err_status = NO_ERROR;
1532  DB_DATETIME src_dt, dest_dt;
1533  TZ_REGION source, dest;
1534 
1535  err_status = tz_str_to_region (source_zone, len_source, &source);
1536  if (err_status != NO_ERROR)
1537  {
1538  return err_status;
1539  }
1540 
1541  err_status = tz_str_to_region (dest_zone, len_dest, &dest);
1542  if (err_status != NO_ERROR)
1543  {
1544  return err_status;
1545  }
1546 
1547  src_dt.date = tz_get_current_date ();
1548  src_dt.time = (*time_source) * 1000;
1549 
1550  err_status = tz_conv_tz_datetime_w_region (&src_dt, &source, &dest, &dest_dt, NULL, NULL);
1551  if (err_status != NO_ERROR)
1552  {
1553  return err_status;
1554  }
1555 
1556  *time_dest = dest_dt.time / 1000;
1557 
1558  return err_status;
1559 }
1560 
1561 /*
1562  * tz_utc_datetimetz_to_local () -
1563  *
1564  * Return: error code
1565  * dt_utc(in): object containing datetime value (in UTC reference)
1566  * tz_id(in): TZ_ID encoded value
1567  * dt_local(out): object containing datetime value (adjusted to timezone contained in tz_id)
1568  *
1569  */
1570 int
1571 tz_utc_datetimetz_to_local (const DB_DATETIME * dt_utc, const TZ_ID * tz_id, DB_DATETIME * dt_local)
1572 {
1573  int total_offset;
1574  int err_status = NO_ERROR;
1575  TZ_DECODE_INFO tz_info;
1576 
1577  tz_decode_tz_id (tz_id, true, &tz_info);
1578 
1579  if (tz_info.type == TZ_REGION_OFFSET)
1580  {
1581  total_offset = tz_info.offset;
1582  if (total_offset == TZ_INVALID_OFFSET)
1583  {
1584 #if !defined (CS_MODE)
1586 #endif
1587  err_status = ER_TZ_INTERNAL_ERROR;
1588  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
1589  }
1590  }
1591  else
1592  {
1593  assert (tz_info.zone.p_zone_off_rule != NULL);
1594  total_offset = tz_info.zone.p_zone_off_rule->gmt_off;
1595 
1596  if (tz_info.zone.p_zone_off_rule->ds_type == DS_TYPE_RULESET_ID && tz_info.zone.p_ds_rule != NULL)
1597  {
1598  total_offset += tz_info.zone.p_ds_rule->save_time;
1599  }
1600  if (tz_info.zone.p_zone_off_rule->ds_type == DS_TYPE_FIXED)
1601  {
1602  total_offset += tz_info.zone.p_zone_off_rule->ds_ruleset;
1603  }
1604  }
1605 
1606  if (dt_utc->date == 0)
1607  {
1608  assert (dt_utc->time == 0);
1609  *dt_local = *dt_utc;
1610  }
1611  else
1612  {
1613  err_status = db_add_int_to_datetime ((DB_DATETIME *) dt_utc, total_offset * 1000, dt_local);
1614  }
1615 
1616  return err_status;
1617 }
1618 
1619 /*
1620  * tz_datetimeltz_to_local () -
1621  *
1622  * Return: error code
1623  * dt_ltz(in): object containing datetime value in UTC representing a datetime in local timezone
1624  * dt_local(out): object containing datetime value (adjusted to session timezone)
1625  *
1626  */
1627 int
1629 {
1630  int error = NO_ERROR;
1631  TZ_ID ses_tz_id;
1632 
1633  error = tz_create_session_tzid_for_datetime (dt_ltz, true, &ses_tz_id);
1634  if (error != NO_ERROR)
1635  {
1636  return error;
1637  }
1638 
1639  return tz_utc_datetimetz_to_local (dt_ltz, &ses_tz_id, dt_local);
1640 }
1641 
1642 /*
1643  * tz_zone_info_to_str () - Print a timezone decoded information into a string
1644  *
1645  * Return: print characters
1646  * tz_info(in): object containing timezone info
1647  * tz_str(in/out): buffer string to print in
1648  * tz_str_size(in): size of buffer
1649  *
1650  */
1651 static int
1652 tz_zone_info_to_str (const TZ_DECODE_INFO * tz_info, char *tz_str, const int tz_str_size)
1653 {
1654  const TZ_DATA *tzd = tz_get_data ();
1655  int zone_name_size;
1656  int zone_id;
1657  int zone_offset_id;
1658  int dst_format_size;
1659  int total_len;
1660  TZ_TIMEZONE *timezone;
1661  TZ_OFFSET_RULE *zone_off_rule;
1662  char dst_format[TZ_MAX_FORMAT_SIZE];
1663  const char *p_dst_format = NULL;
1664 
1665  if (tz_info->type == TZ_REGION_OFFSET)
1666  {
1667  int offset = tz_info->offset;
1668  int hour, min, sec, n;
1669  char sign;
1670 
1671  if (offset == TZ_INVALID_OFFSET)
1672  {
1673  return -1;
1674  }
1675 
1676  sign = (offset < 0) ? '-' : '+';
1677  assert (offset >= TZ_MIN_OFFSET && offset <= TZ_MAX_OFFSET);
1678 
1679  offset = (offset < 0) ? (-offset) : offset;
1680  db_time_decode ((DB_TIME *) (&offset), &hour, &min, &sec);
1681 
1682  if (sec > 0)
1683  {
1684  n = sprintf (tz_str, "%c%02d:%02d:%02d", sign, hour, min, sec);
1685  }
1686  else
1687  {
1688  n = sprintf (tz_str, "%c%02d:%02d", sign, hour, min);
1689  }
1690 
1691  return n;
1692  }
1693 
1694  if (tzd == NULL)
1695  {
1696  return -1;
1697  }
1698 
1699  zone_id = tz_info->zone.zone_id;
1700  zone_offset_id = tz_info->zone.offset_id;
1701  zone_name_size = strlen (tzd->names[zone_id].name);
1702 
1703  timezone = &(tzd->timezones[tzd->names[zone_id].zone_id]);
1704  zone_off_rule = &(tzd->offset_rules[timezone->gmt_off_rule_start + zone_offset_id]);
1705 
1706  p_dst_format = zone_off_rule->std_format;
1707  if (zone_off_rule->ds_type == DS_TYPE_RULESET_ID)
1708  {
1709  TZ_DS_RULESET *ds_ruleset;
1710  TZ_DS_RULE *ds_rule = NULL;
1711  int dst_id = tz_info->zone.dst_id;
1712  const char *ds_abbr = NULL;
1713 
1714  ds_ruleset = &(tzd->ds_rulesets[zone_off_rule->ds_ruleset]);
1715  if (dst_id < ds_ruleset->count)
1716  {
1717  ds_rule = &(tzd->ds_rules[dst_id + ds_ruleset->index_start]);
1718  ds_abbr = ds_rule->letter_abbrev;
1719  }
1720 
1721  if (zone_off_rule->var_format != NULL)
1722  {
1723  if (ds_abbr == NULL)
1724  {
1725  p_dst_format = NULL;
1726  }
1727  else
1728  {
1729  snprintf (dst_format, sizeof (dst_format) - 1, zone_off_rule->var_format,
1730  (ds_abbr != NULL && *ds_abbr != '-') ? ds_abbr : "");
1731  p_dst_format = dst_format;
1732  }
1733  }
1734  else
1735  {
1736  if (ds_rule != NULL && ds_rule->save_time != 0 && zone_off_rule->save_format != NULL)
1737  {
1738  p_dst_format = zone_off_rule->save_format;
1739  }
1740  }
1741  }
1742 
1743  if (p_dst_format != NULL)
1744  {
1745  dst_format_size = strlen (p_dst_format);
1746  }
1747  else
1748  {
1749  dst_format_size = 0;
1750  }
1751 
1752  if (dst_format_size > 0)
1753  {
1754  total_len = dst_format_size + zone_name_size + 2;
1755  }
1756  else
1757  {
1758  total_len = zone_name_size + 1;
1759  }
1760 
1761  if (total_len > tz_str_size)
1762  {
1763  /* silent return */
1764  return -1;
1765  }
1766 
1767  if (p_dst_format != NULL)
1768  {
1769  snprintf (tz_str, tz_str_size, "%s %s", tzd->names[zone_id].name, p_dst_format);
1770  }
1771  else
1772  {
1773  snprintf (tz_str, tz_str_size, "%s", tzd->names[zone_id].name);
1774  }
1775 
1776  return total_len - 1;
1777 }
1778 
1779 /*
1780  * tz_id_to_str () - Print a timezone compressed identifier into a string
1781  *
1782  * Return: printed characters
1783  * tz_id(in): complete valid zone identifier
1784  * tz_str(in): buffer string to print in
1785  * tz_str_size(in): size of buffer
1786  *
1787  */
1788 int
1789 tz_id_to_str (const TZ_ID * tz_id, char *tz_str, const int tz_str_size)
1790 {
1791  TZ_DECODE_INFO tz_info;
1792 
1793  tz_decode_tz_id (tz_id, true, &tz_info);
1794  return tz_zone_info_to_str (&tz_info, tz_str, tz_str_size);
1795 }
1796 
1797 /*
1798  * tz_datetimetz_fix_zone () - Adjusts timezone identifier part of a DATETIMETZ object so that offset and DST parts
1799  * are adjusted to new DATETIME
1800  *
1801  * Return: error code
1802  * src_dt_tz(in): datetime value (adjusted to UTC) and timezone identifier
1803  * dest_dt_tz(out): fixed DATETIMETZ value
1804  *
1805  * Note : After an arithmetic operation (DATETIMETZ + number), the DATETIME
1806  * part is changed, but the TZ_ID part remains unchanged and is not
1807  * compatible. This functions adjusts the TZ_ID. If the TZ_ID is of
1808  * offset type, no adjustements are necessary. If TZ_ID is of
1809  * geographic type, only the zone idenfier is kept, while the offset
1810  * and daylight saving rule identifiers are changed according to new
1811  * date. This ensures that the output value is ready to be decoded.
1812  *
1813  */
1814 int
1815 tz_datetimetz_fix_zone (const DB_DATETIMETZ * src_dt_tz, DB_DATETIMETZ * dest_dt_tz)
1816 {
1817  int er_status = NO_ERROR;
1818  TZ_DECODE_INFO tz_info;
1819 
1820  tz_decode_tz_id (&(src_dt_tz->tz_id), false, &tz_info);
1821 
1822  er_status = tz_datetime_utc_conv (&(src_dt_tz->datetime), &tz_info, true, true, &(dest_dt_tz->datetime));
1823  if (er_status != NO_ERROR)
1824  {
1825  return er_status;
1826  }
1827 
1828  tz_encode_tz_id (&tz_info, &(dest_dt_tz->tz_id));
1829 
1830  return er_status;
1831 }
1832 
1833 /*
1834  * tz_timestamptz_fix_zone () - Adjusts timezone identifier part of a DATETIMETZ object so that offset and DST parts
1835  * are adjusted to new DATETIME
1836  *
1837  * Return: error code
1838  * src_ts_tz(in): timestamp value and timezone identifier
1839  * dest_ts_tz(out): fixed TIMESTAMPTZ value
1840  *
1841  */
1842 int
1843 tz_timestamptz_fix_zone (const DB_TIMESTAMPTZ * src_ts_tz, DB_TIMESTAMPTZ * dest_ts_tz)
1844 {
1845  int er_status = NO_ERROR;
1846  DB_DATETIMETZ src_dt_tz, dest_dt_tz;
1847  DB_DATE date;
1848  DB_TIME time;
1849 
1850  db_timestamp_decode_utc (&src_ts_tz->timestamp, &date, &time);
1851  src_dt_tz.datetime.date = date;
1852  src_dt_tz.datetime.time = time * 1000;
1853  src_dt_tz.tz_id = src_ts_tz->tz_id;
1854 
1855  er_status = tz_datetimetz_fix_zone (&src_dt_tz, &dest_dt_tz);
1856  if (er_status != NO_ERROR)
1857  {
1858  return er_status;
1859  }
1860 
1861  date = dest_dt_tz.datetime.date;
1862  time = dest_dt_tz.datetime.time / 1000;
1863 
1864  dest_ts_tz->tz_id = dest_dt_tz.tz_id;
1865  er_status = db_timestamp_encode_utc (&date, &time, &dest_ts_tz->timestamp);
1866 
1867  return er_status;
1868 }
1869 
1870 /*
1871  * Utility functions
1872  */
1873 
1874 /*
1875  * tz_encode_tz_id () - Encodes a timezone decoded information into a compressed timezone identifier (ready for storage)
1876  *
1877  * Return: none
1878  * tz_info(in): object containing decoded timezone info
1879  * tz_id(out): compressed timezone identifier
1880  *
1881  * FFZZZZZZ ZZZZZZZZ OOOOOOOO DDDDDDDD
1882  * F = 01 : TZ_ID is number representing positive offset in seconds
1883  * F = 10 : TZ_ID is number representing negative offset in seconds
1884  * F = 00 : TZ_ID is encoded as ZOD
1885  * F = 11 : not used
1886  * Z = geographical zone id
1887  * O = GMT offset sub-rule id
1888  * D = DST sub-rule id
1889  */
1890 static void
1891 tz_encode_tz_id (const TZ_DECODE_INFO * tz_info, TZ_ID * tz_id)
1892 {
1893  if (tz_info->type == TZ_REGION_OFFSET)
1894  {
1895  // *INDENT-OFF*
1896  unsigned int offset = static_cast<unsigned int> ((tz_info->offset < 0) ? (-tz_info->offset) : tz_info->offset);
1897  // *INDENT-ON*
1898 
1899  offset = offset & TZ_OFFSET_MASK;
1900 
1901  if (tz_info->offset < 0)
1902  {
1903  *tz_id = offset | (0x2 << 30);
1904  }
1905  else
1906  {
1907  *tz_id = offset | (0x1 << 30);
1908  }
1909  }
1910  else
1911  {
1912  int zone_id = tz_info->zone.zone_id;
1913  int offset_id = tz_info->zone.offset_id;
1914  int dst_id = tz_info->zone.dst_id;
1915 
1916  zone_id = zone_id & TZ_ZONE_ID_MAX;
1917  offset_id = offset_id & TZ_OFFSET_ID_MAX;
1918  dst_id = dst_id & TZ_DS_ID_MAX;
1919 
1920  *tz_id = dst_id | (offset_id << 8) | (zone_id) << 16;
1921  }
1922 }
1923 
1924 /*
1925  * tz_encode_tz_region () - encodes a partial timezone decoding struct into a timezone region
1926  *
1927  * Return: none
1928  * tz_info(in): object containing decoded timezone info
1929  * tz_region(out): time zone region
1930  */
1931 static void
1932 tz_encode_tz_region (const TZ_DECODE_INFO * tz_info, TZ_REGION * tz_region)
1933 {
1934  tz_region->type = tz_info->type;
1935  if (tz_info->type == TZ_REGION_OFFSET)
1936  {
1937  tz_region->offset = tz_info->offset;
1938  }
1939  else
1940  {
1941  assert (tz_info->zone.zone_id < TZ_ZONE_ID_MAX);
1942  tz_region->zone_id = tz_info->zone.zone_id;
1943  }
1944 }
1945 
1946 /*
1947  * tz_decode_tz_id () - Decodes a timezone compressed identifier into a structure
1948  *
1949  * Return: none
1950  * tz_id(in): full
1951  * is_full_decode(in): true if full decoding should be performed; otherwise
1952  * only zone identifier is decoded for a geographical TZ_ID
1953  * tz_info(out): object containing decoded timezone info
1954  *
1955  */
1956 static void
1957 tz_decode_tz_id (const TZ_ID * tz_id, const bool is_full_decode, TZ_DECODE_INFO * tz_info)
1958 {
1959  unsigned int val = (unsigned int) *tz_id;
1960  unsigned int flag = (val & TZ_MASK_TZ_ID_FLAG) >> TZ_BIT_SHIFT_TZ_ID_FLAG;
1961 
1962  memset (tz_info, 0, sizeof (tz_info[0]));
1963 
1964  if (flag == 0)
1965  {
1966  tz_info->zone.zone_id = (val & (TZ_ZONE_ID_MAX << 16)) >> 16;
1967  tz_info->zone.offset_id = (val & (TZ_OFFSET_ID_MAX << 8)) >> 8;
1968  tz_info->zone.dst_id = val & TZ_DS_ID_MAX;
1969  tz_info->type = TZ_REGION_ZONE;
1970 
1971  assert (tz_info->zone.zone_id < TZ_ZONE_ID_MAX);
1972 
1973  if (is_full_decode)
1974  {
1975  int zone_id;
1976  int zone_offset_id;
1977  const TZ_DATA *tzd = tz_get_data ();
1978  TZ_TIMEZONE *timezone;
1979  TZ_OFFSET_RULE *zone_off_rule;
1980 
1981  if (tzd == NULL)
1982  {
1983  tz_info->type = TZ_REGION_OFFSET;
1984  tz_info->offset = 0;
1985  return;
1986  }
1987 
1988  zone_id = tzd->names[tz_info->zone.zone_id].zone_id;
1989  zone_offset_id = tz_info->zone.offset_id;
1990 
1991  assert (zone_offset_id >= 0 && zone_offset_id < TZ_OFFSET_ID_MAX);
1992 
1993  timezone = &(tzd->timezones[zone_id]);
1994  tz_info->zone.p_timezone = timezone;
1995 
1996  zone_off_rule = &(tzd->offset_rules[timezone->gmt_off_rule_start + zone_offset_id]);
1997  tz_info->zone.p_zone_off_rule = zone_off_rule;
1998 
1999  if (zone_off_rule->ds_type == DS_TYPE_RULESET_ID)
2000  {
2001  TZ_DS_RULESET *ds_ruleset;
2002  TZ_DS_RULE *ds_rule;
2003  int dst_id;
2004  const char *ds_abbr = NULL;
2005 
2006  ds_ruleset = &(tzd->ds_rulesets[zone_off_rule->ds_ruleset]);
2007  dst_id = tz_info->zone.dst_id;
2008 
2009  /* we may not have a DST rule, if Daylight Saving does not apply */
2010  if (dst_id != TZ_DS_ID_MAX)
2011  {
2012  assert (dst_id >= 0 && dst_id < ds_ruleset->count);
2013  ds_rule = &(tzd->ds_rules[dst_id + ds_ruleset->index_start]);
2014  ds_abbr = ds_rule->letter_abbrev;
2015 
2016  tz_info->zone.p_ds_rule = ds_rule;
2017 
2018  if (zone_off_rule->var_format != NULL)
2019  {
2020  snprintf (tz_info->zone.dst_str, sizeof (tz_info->zone.dst_str) - 1, zone_off_rule->var_format,
2021  (ds_abbr != NULL && *ds_abbr != '-') ? ds_abbr : "");
2022  }
2023  }
2024  }
2025  }
2026  }
2027  else
2028  {
2029  tz_info->type = TZ_REGION_OFFSET;
2030  if (flag == 0x2)
2031  {
2032  /* negative offset */
2033  tz_info->offset = -(int) (val & TZ_OFFSET_MASK);
2034  }
2035  else
2036  {
2037  /* positive offset */
2038  assert (flag == 0x1);
2039  tz_info->offset = val & TZ_OFFSET_MASK;
2040  }
2041  }
2042 }
2043 
2044 /*
2045  * tz_decode_tz_region () - Decodes a timezone region structure into a helper timezone decoder structure
2046  *
2047  * Return: none
2048  * tz_region(in): time zone region
2049  * tz_info(out): object containing partial decoded timezone info
2050  *
2051  */
2052 static void
2053 tz_decode_tz_region (const TZ_REGION * tz_region, TZ_DECODE_INFO * tz_info)
2054 {
2055  tz_info->type = tz_region->type;
2056 
2057  if (tz_region->type == TZ_REGION_OFFSET)
2058  {
2059  tz_info->offset = tz_region->offset;
2060  }
2061  else
2062  {
2063  tz_info->zone.zone_id = tz_region->zone_id;
2064  }
2065 
2066  tz_info->zone.offset_id = TZ_OFFSET_ID_MAX;
2067  tz_info->zone.dst_id = TZ_DS_ID_MAX;
2068  tz_info->zone.p_timezone = NULL;
2069  tz_info->zone.p_zone_off_rule = NULL;
2070  tz_info->zone.p_ds_rule = NULL;
2071  tz_info->zone.dst_str[0] = '\0';
2072 }
2073 
2074 /*
2075  * tz_get_first_weekday_around_date () - find the day of month when a specific weekday occurs
2076  * Returns: -1 if error; otherwise, day of month (0 to 27/28/29/30, depending on the input month.
2077  *
2078  * year(in):
2079  * month(in): month (0-11)
2080  * weekday(in): weekday ( 0 = Sunday through 6 = Saturday)
2081  * ref_day(in): reference day of month (0 based)
2082  *
2083  */
2084 int
2085 tz_get_first_weekday_around_date (const int year, const int month, const int weekday, const int ref_day,
2086  const bool before)
2087 {
2088  int first_weekday = -1;
2089  int wday = -1;
2090 
2091  assert (year >= 1900);
2092 
2093  wday = db_get_day_of_week (year, month + 1, ref_day + 1);
2094  first_weekday = ref_day;
2095 
2096  while (wday != weekday)
2097  {
2098  if (before == true)
2099  {
2100  wday = (wday == TZ_WEEK_DAY_SUN) ? TZ_WEEK_DAY_SAT : (wday - 1);
2101  first_weekday--;
2102  assert (first_weekday >= 0);
2103  }
2104  else
2105  {
2106  wday = (wday + 1) % TZ_WEEK_DAY_COUNT;
2107  first_weekday++;
2108 
2109  assert (first_weekday <
2110  ((month == TZ_MON_FEB) ? (((IS_LEAP_YEAR (year)) ? 29 : 28)) : DAYS_IN_MONTH (month)));
2111  }
2112  }
2113 
2114  return first_weekday;
2115 }
2116 
2117 /*
2118  * tz_str_read_number() - attempts to read an integer value from a string
2119  *
2120  * Returns: error code
2121  * str(in): string to parse
2122  * str_end(in): pointer to end of string (after last character)
2123  * strict(in): true, if no trailing characters allowed
2124  * read_sign(in): true, if shoud read leading sign
2125  * val(out): the integer found in the input string
2126  * str_next(out): reference to the first character after the read integer.
2127  * If no value was read, str_next will reference str.
2128  */
2129 int
2130 tz_str_read_number (const char *str, const char *str_end, const bool strict, const bool read_sign, int *val,
2131  const char **str_next)
2132 {
2133  int cur_val = 0;
2134  const char *str_cursor;
2135  bool is_negative = false;
2136 
2137  assert (str < str_end && !IS_EMPTY_STR (str));
2138 
2139  str_cursor = str;
2140 
2141  if (read_sign == true && str < str_end)
2142  {
2143  if (*str_cursor == '-')
2144  {
2145  is_negative = true;
2146  str_cursor++;
2147  }
2148  else if (*str_cursor == '+')
2149  {
2150  str_cursor++;
2151  }
2152  }
2153 
2154  while (str_cursor < str_end && char_isdigit (*str_cursor))
2155  {
2156  cur_val = cur_val * 10 + (*str_cursor - '0');
2157  str_cursor++;
2158  }
2159 
2160  *val = is_negative ? -cur_val : cur_val;
2161 
2162  *str_next = (char *) str_cursor;
2163 
2164  if (strict && str_cursor == str)
2165  {
2166  return ER_FAILED;
2167  }
2168 
2169  return NO_ERROR;
2170 }
2171 
2172 /*
2173  * tz_str_read_time() - read a time value from an input string. Input time can be hh, hh:mm or hh:mm:ss (s or u)
2174  *
2175  * Returns: ER_FAILED (message error is not set) or NO_ERROR
2176  * str(in): string to parse
2177  * str_end(in): end of string (pointer to first character after string)
2178  * need_minutes(in): true if it is mandatory to read minutes part, otherwise hour specifier is enough
2179  * allow_sec60(in): true if 60 is allowed for the value of seconds, false otherwise
2180  * hour(out): parsed value for hour
2181  * min(out) : parsed value for minutes
2182  * sec(out) : parsed value for seconds
2183  * str_next(out): pointer to the char after the parsed time value
2184  */
2185 int
2186 tz_str_read_time (const char *str, const char *str_end, bool need_minutes, bool allow_sec60, int *hour, int *min,
2187  int *sec, const char **str_next)
2188 {
2189  const char *str_cursor;
2190  int val_read = 0;
2191 
2192  assert (str < str_end && !IS_EMPTY_STR (str));
2193 
2194  *hour = *min = *sec = 0;
2195  str_cursor = str;
2196 
2197  /* read hour part */
2198  if (tz_str_read_number (str_cursor, str_end, true, false, &val_read, str_next) != NO_ERROR)
2199  {
2200  return ER_FAILED;
2201  }
2202  if (val_read < 0 || val_read > 24)
2203  {
2204  return ER_FAILED;
2205  }
2206  *hour = val_read;
2207 
2208  str_cursor = *str_next;
2209  if (*str_cursor != ':')
2210  {
2211  if (!need_minutes && *str_cursor == '\0')
2212  {
2213  return NO_ERROR;
2214  }
2215  /* invalid text representation for time */
2216  return ER_FAILED;
2217  }
2218 
2219  str_cursor++; /* skip colon between hour and minute part */
2220 
2221  /* read minute part */
2222  if (str_cursor >= str_end || IS_EMPTY_STR (str_cursor))
2223  {
2224  /* missing minute token */
2225  return ER_FAILED;
2226  }
2227  if (tz_str_read_number (str_cursor, str_end, true, false, &val_read, str_next) != NO_ERROR)
2228  {
2229  return ER_FAILED;
2230  }
2231  if (val_read < 0 || val_read > 60 || (val_read > 0 && *hour == 24))
2232  {
2233  return ER_FAILED;
2234  }
2235  *min = val_read;
2236 
2237  /* read second part if exists */
2238  str_cursor = *str_next;
2239 
2240  assert (str_cursor <= str_end);
2241  if (str_cursor == str_end)
2242  {
2243  /* reaches end of the given string. This means it does not have second part */
2244  assert (*sec == 0);
2245  return NO_ERROR;
2246  }
2247 
2248  assert (str_cursor < str_end);
2249  if (*str_cursor == ':')
2250  {
2251  /* if there is a token for seconds, read it */
2252  str_cursor++;
2253  if (tz_str_read_number (str_cursor, str_end, true, false, &val_read, str_next) != NO_ERROR)
2254  {
2255  return ER_FAILED;
2256  }
2257  if (val_read < 0 || val_read > (allow_sec60 ? 61 : 60))
2258  {
2259  return ER_FAILED;
2260  }
2261  *sec = val_read;
2262  }
2263 
2264  return NO_ERROR;
2265 }
2266 
2267 /*
2268  * tz_str_to_seconds() - parses a string representing a signed time offset
2269  *
2270  * Returns: ER_FAILED (message error is not set) or NO_ERROR
2271  * str(in): string to parse
2272  * seconds(out): the signed number of seconds that the string represents
2273  * str_next(out): pointer to the first char after the parsed time
2274  * is_offset(in): true if str is a timezone offset, false if it is
2275  * an absolute value
2276  */
2277 int
2278 tz_str_to_seconds (const char *str, const char *str_end, int *seconds, const char **str_next, const bool is_offset)
2279 {
2280  int err_status = NO_ERROR;
2281  int result = 0;
2282  const char *str_cursor = NULL;
2283  int hour = 0, min = 0, sec = 0;
2284  bool is_negative = false;
2285 
2286  assert (str != NULL);
2287 
2288  str_cursor = str;
2289  if (str_cursor < str_end && *str_cursor == '-')
2290  {
2291  is_negative = true;
2292  str_cursor++;
2293  }
2294  if (str_cursor < str_end && *str_cursor == '+')
2295  {
2296  str_cursor++;
2297  }
2298 
2299  err_status = tz_str_read_time (str_cursor, str_end, false, false, &hour, &min, &sec, str_next);
2300  if (err_status != NO_ERROR)
2301  {
2302  return err_status;
2303  }
2304  if (is_offset == true)
2305  {
2306  if (is_negative == true && -(hour * 3600 + min * 60 + sec) < TZ_MIN_OFFSET)
2307  {
2308  return ER_FAILED;
2309  }
2310  if (is_negative == false && (hour * 3600 + min * 60 + sec) > TZ_MAX_OFFSET)
2311  {
2312  return ER_FAILED;
2313  }
2314  }
2315 
2316  result = sec + min * 60 + hour * 3600;
2317 
2318  *seconds = is_negative ? -result : result;
2319  return err_status;
2320 }
2321 
2322 /*
2323  * tz_get_ds_change_julian_date () - Computes the exact date when a daylight saving rule applies in year and
2324  * the difference between the src_julian_date and the computed date
2325  * Returns: error code
2326  * src_julian_date(in): source julian date
2327  * ds_rule(in): daylight saving rule
2328  * year(in): current year to apply rule
2329  * ds_rule_julian_date(out): julian date
2330  * date_diff(out): date difference between the two dates
2331  */
2332 int
2333 tz_get_ds_change_julian_date_diff (const int src_julian_date, const TZ_DS_RULE * ds_rule, const int year,
2334  int *ds_rule_julian_date, full_date_t * date_diff)
2335 {
2336  int ds_rule_day;
2337  int ds_rule_month = ds_rule->in_month;
2338 
2339  /* get exact julian date/time for this rule in year 'local_year' */
2340  if (ds_rule->change_on.type == TZ_DS_TYPE_FIXED)
2341  {
2342  ds_rule_day = ds_rule->change_on.day_of_month;
2343  }
2344  else
2345  {
2346  int ds_rule_weekday, day_month_bound;
2347  bool before = (ds_rule->change_on.type == TZ_DS_TYPE_VAR_SMALLER) ? true : false;
2348  ds_rule_weekday = ds_rule->change_on.day_of_week;
2349  day_month_bound = ds_rule->change_on.day_of_month;
2350 
2351  if (ds_rule->change_on.type == TZ_DS_TYPE_VAR_SMALLER && ds_rule_month == TZ_MON_FEB && IS_LEAP_YEAR (year)
2352  && day_month_bound == 27)
2353  {
2354  day_month_bound++;
2355  }
2356 
2357  ds_rule_day = tz_get_first_weekday_around_date (year, ds_rule_month, ds_rule_weekday, day_month_bound, before);
2358 
2359  if (ds_rule_day == -1)
2360  {
2362  return ER_TZ_INTERNAL_ERROR;
2363  }
2364  }
2365 
2366  *ds_rule_julian_date = julian_encode (1 + ds_rule_month, 1 + ds_rule_day, year);
2367 
2368  if (date_diff != NULL)
2369  {
2370  *date_diff = FULL_DATE (src_julian_date, 0) - FULL_DATE (*ds_rule_julian_date, 0);
2371  }
2372 
2373  return NO_ERROR;
2374 }
2375 
2376 /*
2377  * tz_fast_find_ds_rule () - Performs a search to find the daylight saving rule for which a certain date applies to
2378  *
2379  * Returns: error code
2380  * tzd(in): Daylight saving data context
2381  * ds_ruleset(in): set of daylight saving rules
2382  * src_julian_date(in): julian date for which we search a rule
2383  * src_year(in): year of date
2384  * src_month(in): month of date
2385  * ds_rule_id(out): found rule
2386  */
2387 static int
2388 tz_fast_find_ds_rule (const TZ_DATA * tzd, const TZ_DS_RULESET * ds_ruleset, const int src_julian_date,
2389  const int src_year, const int src_month, int *ds_rule_id)
2390 {
2391  int curr_ds_id;
2392  int er_status = NO_ERROR;
2393  TZ_DS_RULE *curr_ds_rule;
2394  full_date_t smallest_date_diff = -1;
2395  int year_to_apply_rule = 0;
2396  full_date_t second_best_date_diff = -1;
2397  int second_best_ds_id = -1;
2398 
2399  *ds_rule_id = -1;
2400 
2401  if ((src_year > ds_ruleset->to_year_max && src_month > TZ_MON_JAN) || (src_year > ds_ruleset->to_year_max + 1))
2402  {
2403  goto exit;
2404  }
2405 
2406  for (curr_ds_id = 0; curr_ds_id < ds_ruleset->count; curr_ds_id++)
2407  {
2408  int ds_rule_julian_date;
2409  full_date_t date_diff;
2410 
2411  assert (curr_ds_id + ds_ruleset->index_start < tzd->ds_rule_count);
2412  curr_ds_rule = &(tzd->ds_rules[curr_ds_id + ds_ruleset->index_start]);
2413 
2414  if (src_year + 1 < curr_ds_rule->from_year)
2415  {
2416  /* no more rules will match */
2417  break;
2418  }
2419 
2420  if (src_year - 1 > curr_ds_rule->to_year
2421  || (src_year > ds_ruleset->to_year_max && curr_ds_rule->in_month < TZ_MON_DEC))
2422  {
2423  full_date_t diff;
2424  full_date_t ds_rule_date = 0;
2425 
2426  /* We don't need here the date difference so we use only rule date */
2427  er_status =
2428  tz_get_ds_change_julian_date_diff (0, curr_ds_rule, curr_ds_rule->to_year, &ds_rule_julian_date, NULL);
2429  if (er_status != NO_ERROR)
2430  {
2431  goto exit;
2432  }
2433 
2434  ds_rule_date = FULL_DATE (ds_rule_julian_date, curr_ds_rule->at_time);
2435  diff = FULL_DATE (src_julian_date, 0) - ds_rule_date;
2436 
2437  if (second_best_date_diff == -1 || diff < second_best_date_diff)
2438  {
2439  second_best_date_diff = diff;
2440  second_best_ds_id = curr_ds_id;
2441  }
2442 
2443  /* this rule cannot apply */
2444  continue;
2445  }
2446  else if (src_year < curr_ds_rule->from_year && curr_ds_rule->in_month > TZ_MON_JAN)
2447  {
2448  continue;
2449  }
2450 
2451  year_to_apply_rule = get_year_to_apply_rule (src_year, curr_ds_rule);
2452  er_status =
2453  tz_get_ds_change_julian_date_diff (src_julian_date, curr_ds_rule, year_to_apply_rule, &ds_rule_julian_date,
2454  &date_diff);
2455  if (er_status != NO_ERROR)
2456  {
2457  goto exit;
2458  }
2459 
2460  if (date_diff < 0 && curr_ds_rule->from_year < year_to_apply_rule)
2461  {
2462  /* if DS rule does not apply to current year try previous year */
2463  er_status =
2464  tz_get_ds_change_julian_date_diff (src_julian_date, curr_ds_rule, year_to_apply_rule - 1,
2465  &ds_rule_julian_date, &date_diff);
2466  if (er_status != NO_ERROR)
2467  {
2468  goto exit;
2469  }
2470  }
2471 
2472  if (date_diff >= DATE_DIFF_MATCH_SAFE_THRESHOLD_SEC
2473  && (smallest_date_diff == -1 || date_diff < smallest_date_diff))
2474  {
2475  /* a date difference of at least two days */
2476  *ds_rule_id = curr_ds_id;
2477  smallest_date_diff = date_diff;
2478  }
2479  }
2480  if (*ds_rule_id == -1)
2481  {
2482  *ds_rule_id = second_best_ds_id;
2483  }
2484 
2485 exit:
2486  return er_status;
2487 }
2488 
2489 /*
2490  * tz_check_ds_match_string () - Checks if user supplied daylight saving string specifier matches the DS rule
2491  *
2492  * Returns: true if the DS string matches with the selected offset and DS rule
2493  * off_rule(in): Offset rule
2494  * ds_rule(in): daylight saving rule
2495  * ds_string(in): daylight saving specifier (user source)
2496  * default_abrev(in): default abbreviation in case ds_rule is NULL
2497  */
2498 static bool
2499 tz_check_ds_match_string (const TZ_OFFSET_RULE * off_rule, const TZ_DS_RULE * ds_rule, const char *ds_string,
2500  const char *default_abrev)
2501 {
2502  bool rule_matched = true;
2503  const char *letter_abrev = NULL;
2504 
2505  if (ds_rule != NULL && ds_rule->letter_abbrev != NULL && *ds_rule->letter_abbrev != '-')
2506  {
2507  letter_abrev = ds_rule->letter_abbrev;
2508  }
2509  else if (ds_rule == NULL && *default_abrev != '-')
2510  {
2511  letter_abrev = default_abrev;
2512  }
2513 
2514  if (off_rule->var_format != NULL)
2515  {
2516  char rule_dst_format[TZ_MAX_FORMAT_SIZE];
2517 
2518  if (letter_abrev != NULL)
2519  {
2520  snprintf (rule_dst_format, sizeof (rule_dst_format) - 1, off_rule->var_format, letter_abrev);
2521  }
2522  else
2523  {
2524  snprintf (rule_dst_format, sizeof (rule_dst_format) - 1, off_rule->var_format, "");
2525  }
2526 
2527  if (strcasecmp (rule_dst_format, ds_string) != 0)
2528  {
2529  /* not matching with variable format */
2530  rule_matched = false;
2531  }
2532  }
2533  else if (off_rule->save_format != NULL && ds_rule->save_time != 0
2534  && strcasecmp (off_rule->save_format, ds_string) != 0)
2535  {
2536  /* not matching with DST format */
2537  rule_matched = false;
2538  }
2539  else if (off_rule->std_format != NULL && ds_rule->save_time == 0 && strcasecmp (off_rule->std_format, ds_string) != 0)
2540  {
2541  /* not matching with standard format */
2542  rule_matched = false;
2543  }
2544 
2545  return rule_matched;
2546 }
2547 
2548 /*
2549  * tz_offset_with_fixed_ds () - Returns an offset that will be used to transform a date into either UTC time reference
2550  * or local time reference
2551  *
2552  * Returns: an offset
2553  * src_is_utc(in): true if UTC time reference, false otherwise
2554  * until_time_type(in): time type of the offset rule
2555  * gmt_offset_sec(in): gmt offset of the offset rule
2556  * ds_save_time(in): daylight saving time
2557  */
2558 static int
2559 tz_offset (const bool src_is_utc, const TZ_TIME_TYPE until_time_type, const int gmt_offset_sec, const int ds_save_time)
2560 {
2561  int offset = 0;
2562 
2563  if (src_is_utc == true)
2564  {
2565  if (until_time_type == TZ_TIME_TYPE_LOCAL_STD)
2566  {
2567  offset += gmt_offset_sec;
2568  }
2569  else if (until_time_type == TZ_TIME_TYPE_LOCAL_WALL)
2570  {
2571  offset += gmt_offset_sec + ds_save_time;
2572  }
2573  }
2574  else if (src_is_utc == false)
2575  {
2576  if (until_time_type == TZ_TIME_TYPE_UTC)
2577  {
2578  offset -= gmt_offset_sec + ds_save_time;
2579  }
2580  else if (until_time_type == TZ_TIME_TYPE_LOCAL_STD)
2581  {
2582  offset -= ds_save_time;
2583  }
2584  }
2585 
2586  return offset;
2587 }
2588 
2589 /*
2590  * get_date_diff_from_ds_rule () - Returns the date difference between a source date and the date when applying
2591  * a daylight saving rule using from_year or to_year
2592  *
2593  * Returns: error or no error
2594  * src_julian_date(in): input source date
2595  * src_time_sec(in): input source time
2596  * ds_rule(in): input daylight saving rule
2597  * direction(in): flag that tells in which direction to search
2598  * date_diff(out): date difference
2599  */
2600 static int
2601 get_date_diff_from_ds_rule (const int src_julian_date, const int src_time_sec, const TZ_DS_RULE * ds_rule,
2602  const DS_SEARCH_DIRECTION direction, full_date_t * date_diff)
2603 {
2604  int ds_rule_julian_date;
2605  int year, err_status = NO_ERROR;
2606  full_date_t ds_rule_date;
2607 
2608  if (direction == FORWARD)
2609  {
2610  year = ds_rule->from_year;
2611  }
2612  else
2613  {
2614  year = ds_rule->to_year;
2615  }
2616 
2617  /* We don't need here the date difference so we use only rule date */
2618  err_status = tz_get_ds_change_julian_date_diff (0, ds_rule, year, &ds_rule_julian_date, NULL);
2619  if (err_status != NO_ERROR)
2620  {
2621  goto exit;
2622  }
2623 
2624  ds_rule_date = FULL_DATE (ds_rule_julian_date, ds_rule->at_time);
2625  *date_diff = FULL_DATE (src_julian_date, src_time_sec) - ds_rule_date;
2626 
2627  if (direction == FORWARD)
2628  {
2629  *date_diff = -(*date_diff);
2630  }
2631 
2632 exit:
2633  return err_status;
2634 }
2635 
2636 /*
2637  * get_closest_ds_rule() - Returns the id of the closest daylight saving rule in the ds_ruleset relative to to_year
2638  * or from_year
2639  *
2640  * Returns: the id of the rule or -1 in case of error
2641  * src_julian_date(in): input source date
2642  * src_time_sec(in): input source time
2643  * ds_ruleset(in): input ds_ruleset
2644  * tzd(in): pointer to the tzdata
2645  * direction(in): input flag that tells us in which direction to search
2646  */
2647 static int
2648 get_closest_ds_rule (const int src_julian_date, const int src_time_sec, const TZ_DS_RULESET * ds_ruleset,
2649  const TZ_DATA * tzd, const DS_SEARCH_DIRECTION direction)
2650 {
2651  int curr_ds_id = 0;
2652  int closest_ds_rule_id = 0;
2653  TZ_DS_RULE *ds_rule;
2654  full_date_t best_diff = -1;
2655  full_date_t date_diff;
2656  int err_status = NO_ERROR;
2657 
2658  for (; curr_ds_id < ds_ruleset->count; curr_ds_id++)
2659  {
2660  ds_rule = &(tzd->ds_rules[curr_ds_id + ds_ruleset->index_start]);
2661 
2662  err_status = get_date_diff_from_ds_rule (src_julian_date, src_time_sec, ds_rule, direction, &date_diff);
2663  if (err_status != NO_ERROR)
2664  {
2665  return -1;
2666  }
2667  if (direction == FORWARD && ds_rule->save_time != 0)
2668  {
2669  continue;
2670  }
2671  if (best_diff == -1 || date_diff < best_diff)
2672  {
2673  best_diff = date_diff;
2674  closest_ds_rule_id = curr_ds_id;
2675  }
2676  }
2677 
2678  return closest_ds_rule_id;
2679 }
2680 
2681 /*
2682  * get_saving_time_from_offset_rule() - Computes the daylight saving time for the last day when the input offset
2683  * rule applies
2684  *
2685  * Returns: error or no error
2686  * offset_rule(in): input offset rule
2687  * tzd(in): timezone data
2688  * save_time(out): output daylight saving time
2689  *
2690  */
2691 static int
2692 get_saving_time_from_offset_rule (const TZ_OFFSET_RULE * offset_rule, const TZ_DATA * tzd, int *save_time)
2693 {
2694  int err_status = NO_ERROR;
2695 
2696  *save_time = 0;
2697  if (offset_rule->ds_type == DS_TYPE_RULESET_ID)
2698  {
2699  int ds_rule_id = -1;
2700  TZ_DS_RULESET *ds_ruleset_off_rule;
2701  int offset_rule_src_year;
2702  int offset_rule_src_month;
2703 
2704  julian_decode (offset_rule->julian_date, &offset_rule_src_month, NULL, &offset_rule_src_year, NULL);
2705  ds_ruleset_off_rule = &(tzd->ds_rulesets[offset_rule->ds_ruleset]);
2706 
2707  err_status =
2708  tz_fast_find_ds_rule (tzd, ds_ruleset_off_rule, offset_rule->julian_date, offset_rule_src_year,
2709  offset_rule_src_month, &ds_rule_id);
2710  if (err_status != NO_ERROR)
2711  {
2712  goto exit;
2713  }
2714 
2715  if (ds_rule_id != -1)
2716  {
2717  TZ_DS_RULE *ds_rule;
2718 
2719  assert (ds_rule_id + ds_ruleset_off_rule->index_start < tzd->ds_rule_count);
2720 
2721  ds_rule = &(tzd->ds_rules[ds_rule_id + ds_ruleset_off_rule->index_start]);
2722  *save_time = ds_rule->save_time;
2723  }
2724  }
2725  else
2726  {
2727  *save_time = offset_rule->ds_ruleset;
2728  }
2729 exit:
2730  return err_status;
2731 }
2732 
2733 /*
2734  * is_in_overlap_interval() - Verifies if a specific date is in the overlap interval between two offset rules
2735  *
2736  * Returns: true or false
2737  * time_type(in): time reference
2738  * offset_rule_diff(in): time difference between the date and the time when the first offset rule ends
2739  * gmt_diff(in): offset time difference between the two offset rules
2740  * save_time_diff(in): daylight saving time difference between the two offset rules
2741  *
2742  */
2743 static bool
2744 is_in_overlap_interval (const TZ_TIME_TYPE time_type, const full_date_t offset_rule_diff, const full_date_t gmt_diff,
2745  const int save_time_diff)
2746 {
2747  full_date_t add_time = 0;
2748  bool overlap = true;
2749 
2750  if (time_type == TZ_TIME_TYPE_LOCAL_STD)
2751  {
2752  add_time = save_time_diff;
2753  }
2754  else if (time_type == TZ_TIME_TYPE_UTC)
2755  {
2756  add_time = gmt_diff + save_time_diff;
2757  }
2758 
2759  if (gmt_diff + save_time_diff > 0 || (ABS (offset_rule_diff + add_time) > ABS (gmt_diff + save_time_diff)))
2760  {
2761  overlap = false;
2762  }
2763 
2764  return overlap;
2765 }
2766 
2767 /*
2768  * get_year_to_apply_rule() - Computes the year in which to apply a daylight saving rule given the source year
2769  *
2770  *
2771  * Returns: the year in which to apply the daylight saving rule
2772  * src_year(in): source year
2773  * ds_rule(in): daylight saving rule
2774  *
2775  */
2776 static int
2777 get_year_to_apply_rule (const int src_year, const TZ_DS_RULE * ds_rule)
2778 {
2779  int year_to_apply_rule;
2780 
2781  if (src_year <= ds_rule->to_year)
2782  {
2783  if (src_year >= ds_rule->from_year)
2784  {
2785  year_to_apply_rule = src_year;
2786  }
2787  else
2788  {
2789  year_to_apply_rule = ds_rule->from_year;
2790  }
2791  }
2792  else
2793  {
2794  year_to_apply_rule = src_year - 1;
2795  }
2796 
2797  return year_to_apply_rule;
2798 }
2799 
2800 /*
2801  * tz_datetime_utc_conv () -
2802  *
2803  * Return: error code
2804  * src_dt(in): object containing source datetime value;
2805  * if 'src_is_utc' is true, than is UTC datetime, otherwise is local datetime
2806  * tz_info(in/out): (partial) decoded timezone info associated with source datetime, additional information is
2807  * changed/added after conversion
2808  * src_is_utc(in): true if 'src_dt' is in UTC time reference, false if src_dt is in local time reference
2809  * only_tz_adjust(in): true if only timezone adjustment is desired, datetime itself is not changed (used in context of
2810  * datetime arithmetic)
2811  * dt_dest(out): object containing destination datetime
2812  *
2813  */
2814 static int
2815 tz_datetime_utc_conv (const DB_DATETIME * src_dt, TZ_DECODE_INFO * tz_info, bool src_is_utc, bool only_tz_adjust,
2816  DB_DATETIME * dest_dt)
2817 {
2818  int src_julian_date, rule_julian_date;
2819  int src_time_sec, rule_time_sec;
2820  int src_year;
2821  int src_month;
2822  int gmt_std_offset_sec;
2823  int total_offset_sec;
2824  int err_status = NO_ERROR;
2825  int curr_offset_id = -1;
2826  int curr_ds_id = -1, applying_ds_id = -1;
2827  full_date_t applying_date_diff = -1;
2828  TZ_TIMEZONE *timezone;
2829  const TZ_DATA *tzd;
2830  TZ_OFFSET_RULE *curr_off_rule = NULL, *next_off_rule = NULL;
2831  TZ_OFFSET_RULE *prev_off_rule = NULL;
2832  TZ_DS_RULESET *ds_ruleset;
2833  TZ_DS_RULE *curr_ds_rule, *applying_ds_rule;
2834  bool check_user_dst = false;
2835  bool applying_with_prev_year = false;
2836  bool applying_is_in_leap_interval = false;
2837  int save_time = 0, src_offset_curr_off_rule = 0;
2838  int src_offset_prev_off_rule = 0;
2839  int leap_offset_rule_interval = 0;
2840  int prev_rule_julian_date = 0, prev_rule_time_sec = 0;
2841  bool try_offset_rule_overlap = false;
2842  int second_best_applying_ds_id = -1;
2843  full_date_t second_best_applying_date_diff = -1;
2844  TZ_DS_RULE *second_best_applying_ds_rule = NULL;
2845  int offset_rule_counter = 0;
2846  TZ_OFFSET_RULE *offset_rules[2] = { NULL };
2847 
2848  if (tz_info->type == TZ_REGION_OFFSET)
2849  {
2850  /* keep offset and zone decode info */
2851  total_offset_sec = tz_info->offset;
2852  if (total_offset_sec == TZ_INVALID_OFFSET)
2853  {
2854 #if !defined (CS_MODE)
2856 #endif
2857  err_status = ER_TZ_INTERNAL_ERROR;
2858  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
2859  }
2860  goto exit;
2861  }
2862 
2863  assert (tz_info->type == TZ_REGION_ZONE);
2864 
2865  tzd = tz_get_data ();
2866 
2867  if (tzd == NULL)
2868  {
2869  err_status = ER_TZ_INTERNAL_ERROR;
2870  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
2871  goto exit;
2872  }
2873 
2874  if ((src_dt->time > MILLIS_IN_A_DAY))
2875  {
2876  err_status = ER_TIME_CONVERSION;
2878  goto exit;
2879  }
2880  /* start decoding zone , GMT offset id, DST id */
2881  assert ((int) tz_info->zone.zone_id < tzd->name_count);
2882  timezone = &(tzd->timezones[tzd->names[tz_info->zone.zone_id].zone_id]);
2883 
2884  assert (timezone->gmt_off_rule_count > 0);
2885 
2886  src_julian_date = src_dt->date;
2887  src_time_sec = src_dt->time / 1000;
2888 
2889  for (curr_offset_id = 0; curr_offset_id < timezone->gmt_off_rule_count; curr_offset_id++)
2890  {
2891  assert (timezone->gmt_off_rule_start + curr_offset_id < tzd->offset_rule_count);
2892  prev_off_rule = curr_off_rule;
2893  curr_off_rule = &(tzd->offset_rules[timezone->gmt_off_rule_start + curr_offset_id]);
2894 
2895  if (curr_off_rule->until_flag == UNTIL_EXPLICIT)
2896  {
2897  rule_julian_date = curr_off_rule->julian_date;
2898  rule_time_sec = (curr_off_rule->until_hour * 60 + curr_off_rule->until_min) * 60 + curr_off_rule->until_sec;
2899  }
2900  else
2901  {
2902  rule_julian_date = TZ_MAX_JULIAN_DATE;
2903  rule_time_sec = 0;
2904  }
2905 
2906  /* add a safety buffer of 1 julian day */
2907  if (src_julian_date <= rule_julian_date + 1)
2908  {
2909  /* this is a candidate, we still have to check the exact time when rule ends */
2910  if (curr_off_rule->until_flag == UNTIL_EXPLICIT)
2911  {
2912  /* set also next */
2913  assert (curr_offset_id < timezone->gmt_off_rule_count - 1);
2914  assert (timezone->gmt_off_rule_start + curr_offset_id + 1 < tzd->offset_rule_count);
2915  next_off_rule = &(tzd->offset_rules[timezone->gmt_off_rule_start + curr_offset_id + 1]);
2916  if (timezone->gmt_off_rule_start + curr_offset_id + 2 < tzd->offset_rule_count)
2917  {
2918  offset_rules[0] = &(tzd->offset_rules[timezone->gmt_off_rule_start + curr_offset_id + 2]);
2919  }
2920  }
2921  /* rule found */
2922  break;
2923  }
2924  }
2925 
2926  assert (curr_off_rule != NULL);
2927  assert (next_off_rule != NULL || curr_off_rule->until_flag == UNTIL_INFINITE);
2928 
2929  julian_decode (src_julian_date, &src_month, NULL, &src_year, NULL);
2930 
2931 detect_dst:
2932  if (curr_off_rule->until_flag == UNTIL_EXPLICIT)
2933  {
2934  rule_julian_date = curr_off_rule->julian_date;
2935  rule_time_sec = (curr_off_rule->until_hour * 60 + curr_off_rule->until_min) * 60 + curr_off_rule->until_sec;
2936  }
2937  else
2938  {
2939  rule_julian_date = TZ_MAX_JULIAN_DATE;
2940  rule_time_sec = 0;
2941  }
2942 
2943  applying_ds_id = -1;
2944  applying_date_diff = -1;
2945  gmt_std_offset_sec = curr_off_rule->gmt_off;
2946  total_offset_sec = gmt_std_offset_sec;
2947  second_best_applying_ds_id = -1;
2948  second_best_applying_date_diff = -1;
2949 
2950  if (prev_off_rule != NULL)
2951  {
2952  prev_rule_julian_date = prev_off_rule->julian_date;
2953  prev_rule_time_sec = (prev_off_rule->until_hour * 60 + prev_off_rule->until_min) * 60 + prev_off_rule->until_sec;
2954  leap_offset_rule_interval = curr_off_rule->gmt_off - prev_off_rule->gmt_off;
2955  }
2956 
2957  if (curr_off_rule->ds_type == DS_TYPE_FIXED)
2958  {
2959  int curr_time_offset;
2960  full_date_t offset_rule_diff;
2961 
2962  curr_time_offset =
2963  tz_offset (src_is_utc, curr_off_rule->until_time_type, gmt_std_offset_sec, curr_off_rule->ds_ruleset);
2964  if (prev_off_rule != NULL)
2965  {
2966  src_offset_prev_off_rule =
2967  tz_offset (src_is_utc, prev_off_rule->until_time_type, gmt_std_offset_sec, curr_off_rule->ds_ruleset);
2968  }
2969 
2970  offset_rule_diff =
2971  FULL_DATE (src_julian_date, src_time_sec + src_offset_prev_off_rule) - FULL_DATE (prev_rule_julian_date,
2972  prev_rule_time_sec);
2973 
2974  if (FULL_DATE (src_julian_date, src_time_sec + curr_time_offset) < FULL_DATE (rule_julian_date, rule_time_sec))
2975  {
2976  int add_ds_save_time_diff = 0;
2977  int prev_rule_save_time = 0;
2978  full_date_t leap = 0;
2979 
2980  if (prev_off_rule != NULL)
2981  {
2982  if (prev_off_rule->until_time_type == TZ_TIME_TYPE_LOCAL_WALL)
2983  {
2984  add_ds_save_time_diff = curr_off_rule->ds_ruleset;
2985  if (offset_rule_diff <= 2 * SECONDS_IN_A_DAY)
2986  {
2987  err_status = get_saving_time_from_offset_rule (prev_off_rule, tzd, &prev_rule_save_time);
2988  if (err_status != NO_ERROR)
2989  {
2990  goto exit;
2991  }
2992  }
2993  add_ds_save_time_diff -= prev_rule_save_time;
2994  leap = leap_offset_rule_interval + add_ds_save_time_diff;
2995  }
2996  else if (prev_off_rule->until_time_type == TZ_TIME_TYPE_LOCAL_STD)
2997  {
2998  leap = leap_offset_rule_interval;
2999  }
3000  }
3001 
3002  if (try_offset_rule_overlap == false && leap >= 0 && (offset_rule_diff < leap))
3003  {
3004  /* invalid time, abort */
3005  err_status = ER_TZ_DURING_OFFSET_RULE_LEAP;
3006  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3007  goto exit;
3008  }
3009 
3010  if (src_is_utc == false && tz_info->zone.dst_str[0] != '\0' && curr_off_rule->var_format == NULL
3011  && (curr_off_rule->std_format == NULL
3012  || strcasecmp (curr_off_rule->std_format, tz_info->zone.dst_str) != 0)
3013  && (curr_off_rule->save_format == NULL
3014  || strcasecmp (curr_off_rule->save_format, tz_info->zone.dst_str) != 0))
3015  {
3016  if (next_off_rule == NULL || try_offset_rule_overlap == true)
3017  {
3018  err_status = ER_TZ_INVALID_COMBINATION;
3019  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3020  goto exit;
3021  }
3022  else
3023  {
3024  try_offset_rule_overlap = true;
3026  goto detect_dst;
3027  }
3028  }
3029  else if (src_is_utc == false && tz_info->zone.dst_str[0] != '\0' && try_offset_rule_overlap == true)
3030  {
3031  bool overlap = false;
3032 
3033  if (ABS (offset_rule_diff) <= 3 * SECONDS_IN_A_DAY)
3034  {
3035  int prev_rule_save_time = 0;
3036  int save_time_diff = 0;
3037 
3038  err_status = get_saving_time_from_offset_rule (prev_off_rule, tzd, &prev_rule_save_time);
3039  if (err_status != NO_ERROR)
3040  {
3041  goto exit;
3042  }
3043 
3044  save_time_diff = curr_off_rule->ds_ruleset - prev_rule_save_time;
3045  overlap =
3046  is_in_overlap_interval (prev_off_rule->until_time_type, offset_rule_diff, leap_offset_rule_interval,
3047  save_time_diff);
3048  }
3049 
3050  if (overlap == false)
3051  {
3052  /* invalid time, abort */
3053  err_status = ER_TZ_INVALID_COMBINATION;
3054  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3055  goto exit;
3056  }
3057  }
3058 
3059  applying_ds_id = 0;
3060  /* finished */
3061  goto exit;
3062  }
3063 
3064  /* try next GMT offset zone */
3065  if (next_off_rule == NULL)
3066  {
3067  err_status = ER_TZ_INVALID_COMBINATION;
3068  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3069  goto exit;
3070  }
3072  goto detect_dst;
3073  }
3074 
3075  /* the zone uses DST rules */
3076  assert (curr_off_rule->ds_type == DS_TYPE_RULESET_ID);
3077  assert (curr_off_rule->ds_ruleset < tzd->ds_ruleset_count);
3078  ds_ruleset = &(tzd->ds_rulesets[curr_off_rule->ds_ruleset]);
3079 
3080  applying_ds_rule = NULL;
3081  second_best_applying_ds_rule = NULL;
3082  if (src_is_utc == false && tz_info->zone.dst_str[0] != '\0')
3083  {
3084  check_user_dst = true;
3085  }
3086 
3087  if ((src_year > ds_ruleset->to_year_max && src_month > TZ_MON_JAN) || (src_year > ds_ruleset->to_year_max + 1))
3088  {
3089  curr_ds_id = ds_ruleset->count;
3090  }
3091  else
3092  {
3093  curr_ds_id = 0;
3094  }
3095 
3096  for (; curr_ds_id < ds_ruleset->count; curr_ds_id++)
3097  {
3098  int ds_rule_julian_date;
3099  full_date_t date_diff;
3100  bool rule_matched = false;
3101  bool is_in_leap_interval = false;
3102  bool check_prev_year = true;
3103  int year_to_apply_rule = 0;
3104  TZ_DS_RULE *wall_ds_rule = NULL;
3105 
3106  assert (curr_ds_id + ds_ruleset->index_start < tzd->ds_rule_count);
3107  curr_ds_rule = &(tzd->ds_rules[curr_ds_id + ds_ruleset->index_start]);
3108 
3109  if (src_year + 1 < curr_ds_rule->from_year)
3110  {
3111  /* no more rules will match */
3112  break;
3113  }
3114 
3115  if (src_year - 1 > curr_ds_rule->to_year
3116  || (src_year > ds_ruleset->to_year_max && curr_ds_rule->in_month < TZ_MON_DEC))
3117  {
3118  full_date_t diff;
3119  full_date_t ds_rule_date = 0;
3120 
3121  /* We don't need here the date difference so we use only rule date */
3122  err_status =
3123  tz_get_ds_change_julian_date_diff (0, curr_ds_rule, curr_ds_rule->to_year, &ds_rule_julian_date, NULL);
3124  if (err_status != NO_ERROR)
3125  {
3126  goto exit;
3127  }
3128 
3129  ds_rule_date = FULL_DATE (ds_rule_julian_date, curr_ds_rule->at_time);
3130  diff = FULL_DATE (src_julian_date, src_time_sec) - ds_rule_date;
3131 
3132  if (second_best_applying_date_diff == -1 || diff < second_best_applying_date_diff)
3133  {
3134  second_best_applying_date_diff = diff;
3135  second_best_applying_ds_id = curr_ds_id;
3136  second_best_applying_ds_rule = curr_ds_rule;
3137  }
3138 
3139  /* this rule cannot apply */
3140  continue;
3141  }
3142  else if (src_year < curr_ds_rule->from_year && curr_ds_rule->in_month > TZ_MON_JAN)
3143  {
3144  continue;
3145  }
3146 
3147  year_to_apply_rule = get_year_to_apply_rule (src_year, curr_ds_rule);
3148  err_status =
3149  tz_get_ds_change_julian_date_diff (src_julian_date, curr_ds_rule, year_to_apply_rule, &ds_rule_julian_date,
3150  &date_diff);
3151  if (err_status != NO_ERROR)
3152  {
3153  goto exit;
3154  }
3155 
3156  if (date_diff >= DATE_DIFF_MATCH_SAFE_THRESHOLD_SEC)
3157  {
3158  /* a date difference of at two days */
3159  rule_matched = true;
3160  }
3161  else if (ABS (date_diff) < DATE_DIFF_MATCH_SAFE_THRESHOLD_SEC)
3162  {
3163  int wall_ds_rule_id;
3164  int wall_safe_julian_date;
3165  full_date_t leap_interval;
3166  int ds_time_offset = 0;
3167  full_date_t ds_rule_date = 0;
3168  full_date_t utc_src_offset = 0;
3169  int save_time = 0;
3170  bool at_time_type_is_utc = false;
3171  int ds_rule_time_offset_curr_off_rule = 0, add_save_time = 0;
3172  int ds_rule_time_offset_prev_off_rule = 0;
3173  int add_leap_offset_rule_interval = 0;
3174 
3175  /* there may be an ambiguity : check the time deviation of a date before current candidate DS rule applies
3176  * (to be safe, 4 days before) */
3177  wall_safe_julian_date = src_julian_date - 2 * DATE_DIFF_MATCH_SAFE_THRESHOLD_DAYS;
3178 
3179  err_status =
3180  tz_fast_find_ds_rule (tzd, ds_ruleset, wall_safe_julian_date, src_year, src_month, &wall_ds_rule_id);
3181  if (err_status != NO_ERROR)
3182  {
3183  goto exit;
3184  }
3185 
3186  if (wall_ds_rule_id != -1)
3187  {
3188  assert (wall_ds_rule_id + ds_ruleset->index_start < tzd->ds_rule_count);
3189  wall_ds_rule = &(tzd->ds_rules[wall_ds_rule_id + ds_ruleset->index_start]);
3190  save_time = wall_ds_rule->save_time;
3191  }
3192  else if (prev_off_rule != NULL)
3193  {
3194  err_status = get_saving_time_from_offset_rule (prev_off_rule, tzd, &save_time);
3195  if (err_status != NO_ERROR)
3196  {
3197  goto exit;
3198  }
3199  add_leap_offset_rule_interval = leap_offset_rule_interval;
3200  }
3201 
3202  if (curr_ds_rule->at_time_type == TZ_TIME_TYPE_UTC)
3203  {
3204  at_time_type_is_utc = true;
3205  }
3206 
3207  if (wall_ds_rule != NULL && prev_off_rule != NULL)
3208  {
3209  bool utc_time = false;
3210  int ds_rule_time_offset;
3211  full_date_t date_diff;
3212  int wall_rule_julian_date;
3213  int add_save_time = 0;
3214  int year_to_apply_rule;
3215 
3216  year_to_apply_rule = get_year_to_apply_rule (src_year, wall_ds_rule);
3217  err_status =
3218  tz_get_ds_change_julian_date_diff (wall_safe_julian_date, wall_ds_rule, year_to_apply_rule,
3219  &wall_rule_julian_date, &date_diff);
3220  if (err_status != NO_ERROR)
3221  {
3222  goto exit;
3223  }
3224  if (date_diff < 0)
3225  {
3226  year_to_apply_rule = year_to_apply_rule - 1;
3227  err_status =
3228  tz_get_ds_change_julian_date_diff (0, wall_ds_rule, year_to_apply_rule, &wall_rule_julian_date,
3229  NULL);
3230  if (err_status != NO_ERROR)
3231  {
3232  goto exit;
3233  }
3234  }
3235 
3236  if (wall_ds_rule->at_time_type == TZ_TIME_TYPE_UTC)
3237  {
3238  utc_time = true;
3239  }
3240 
3241  ds_rule_time_offset = tz_offset (utc_time, prev_off_rule->until_time_type, gmt_std_offset_sec, 0);
3242  date_diff =
3243  FULL_DATE (wall_rule_julian_date,
3244  wall_ds_rule->at_time + ds_rule_time_offset) - FULL_DATE (prev_rule_julian_date,
3245  prev_rule_time_sec);
3246 
3247  if (date_diff < 0)
3248  {
3249  int prev_rule_save_time;
3250 
3251  err_status = get_saving_time_from_offset_rule (prev_off_rule, tzd, &prev_rule_save_time);
3252  if (err_status != NO_ERROR)
3253  {
3254  goto exit;
3255  }
3256 
3257  ds_rule_time_offset =
3258  tz_offset (at_time_type_is_utc, prev_off_rule->until_time_type, gmt_std_offset_sec, save_time);
3259  if (curr_ds_rule->at_time_type == TZ_TIME_TYPE_LOCAL_STD)
3260  {
3261  add_save_time = save_time;
3262  }
3263 
3264  if (FULL_DATE (ds_rule_julian_date, curr_ds_rule->at_time + add_save_time + ds_rule_time_offset) <=
3265  FULL_DATE (prev_rule_julian_date, prev_rule_time_sec))
3266  {
3267  save_time = prev_rule_save_time;
3268  add_leap_offset_rule_interval = leap_offset_rule_interval;
3269  }
3270  }
3271  }
3272 
3273  if (curr_ds_rule->at_time_type == TZ_TIME_TYPE_LOCAL_STD)
3274  {
3275  add_save_time = save_time;
3276  }
3277 
3278  if (prev_off_rule != NULL)
3279  {
3280  ds_rule_time_offset_prev_off_rule =
3281  tz_offset (at_time_type_is_utc, prev_off_rule->until_time_type, gmt_std_offset_sec, save_time);
3282  if (FULL_DATE
3283  (ds_rule_julian_date,
3284  curr_ds_rule->at_time + add_save_time + ds_rule_time_offset_prev_off_rule) >
3285  FULL_DATE (prev_rule_julian_date, prev_rule_time_sec))
3286  {
3287  add_leap_offset_rule_interval = 0;
3288  }
3289  }
3290 
3291  ds_rule_time_offset_curr_off_rule =
3292  tz_offset (at_time_type_is_utc, curr_off_rule->until_time_type, gmt_std_offset_sec, save_time);
3293 
3294  if (FULL_DATE (ds_rule_julian_date, curr_ds_rule->at_time + add_save_time + ds_rule_time_offset_curr_off_rule)
3295  >= FULL_DATE (rule_julian_date, rule_time_sec))
3296  {
3297  continue;
3298  }
3299 
3300  /* the difference between the input date and the rule date must be made in the same time reference, in our
3301  * case it is the local time reference */
3302  /* ds_time_offset is used to adjust the time at which the new daylight saving rule applies */
3303 
3304  if (curr_ds_rule->at_time_type == TZ_TIME_TYPE_UTC)
3305  {
3306  ds_time_offset = gmt_std_offset_sec + curr_ds_rule->save_time;
3307  }
3308  else if (curr_ds_rule->at_time_type == TZ_TIME_TYPE_LOCAL_STD)
3309  {
3310  ds_time_offset = curr_ds_rule->save_time;
3311  }
3312  else if (curr_ds_rule->at_time_type == TZ_TIME_TYPE_LOCAL_WALL)
3313  {
3314  /* wall clock: may indicate either the daylight time or standard time */
3315  ds_time_offset = curr_ds_rule->save_time - save_time;
3316  }
3317  if (curr_ds_rule->at_time_type != TZ_TIME_TYPE_UTC)
3318  {
3319  ds_time_offset += add_leap_offset_rule_interval;
3320  }
3321 
3322  if (src_is_utc == true)
3323  {
3324  /* UTC time always exists, thus we don't need to take into consideration leap interval overlap */
3325  leap_interval = 0;
3326  utc_src_offset = gmt_std_offset_sec + curr_ds_rule->save_time;
3327  }
3328  else
3329  {
3330  leap_interval = save_time - curr_ds_rule->save_time;
3331  leap_interval -= add_leap_offset_rule_interval;
3332  }
3333 
3334  ds_rule_date = FULL_DATE (ds_rule_julian_date, ds_time_offset + curr_ds_rule->at_time);
3335  date_diff = FULL_DATE (src_julian_date, src_time_sec + utc_src_offset) - ds_rule_date;
3336 
3337  if (date_diff >= 0)
3338  {
3339  rule_matched = true;
3340 
3341  if (leap_interval > 0 && date_diff < leap_interval)
3342  {
3343  is_in_leap_interval = true;
3344  }
3345  }
3346  else
3347  {
3348  if (leap_interval < 0 && ABS (date_diff) <= ABS (leap_interval))
3349  {
3350  int offset;
3351 
3352  offset = tz_offset (src_is_utc, curr_off_rule->until_time_type, gmt_std_offset_sec, 0);
3353 
3354  if (FULL_DATE (src_julian_date, src_time_sec + offset) < FULL_DATE (rule_julian_date, rule_time_sec))
3355  {
3356  /* invalid time, abort */
3357  err_status = ER_TZ_DURING_DS_LEAP;
3358  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3359  goto exit;
3360  }
3361  else
3362  {
3363  applying_ds_id = -1;
3364  second_best_applying_ds_id = -1;
3365  break;
3366  }
3367  }
3368  }
3369  }
3370 
3371  match_ds_rule:
3372  if (rule_matched)
3373  {
3374  assert (date_diff >= 0);
3375 
3376  if (applying_date_diff > 0 && date_diff > applying_date_diff && !applying_is_in_leap_interval)
3377  {
3378  /* a better rule was previously found */
3379  continue;
3380  }
3381 
3382  if (is_in_leap_interval || applying_is_in_leap_interval)
3383  {
3384  if (check_user_dst)
3385  {
3386  rule_matched =
3387  tz_check_ds_match_string (curr_off_rule, curr_ds_rule, tz_info->zone.dst_str,
3388  ds_ruleset->default_abrev);
3389  }
3390  else if (applying_ds_id != -1)
3391  {
3392  /* ambiguity : user did not specified a daylight saving; a previous rule was matched, but also the
3393  * current one is; We are during the DS interval change, we choose the one before (timewise) DS
3394  * change is performed */
3395  if (applying_date_diff > date_diff || applying_with_prev_year)
3396  {
3397  rule_matched = false;
3398  }
3399  }
3400  }
3401 
3402  if (rule_matched
3403  && (applying_date_diff < 0 || date_diff < applying_date_diff || applying_is_in_leap_interval))
3404  {
3405  if (is_in_leap_interval == true && wall_ds_rule != NULL && check_user_dst == true
3406  && tz_check_ds_match_string (curr_off_rule, wall_ds_rule, tz_info->zone.dst_str,
3407  ds_ruleset->default_abrev) == true)
3408  {
3409  continue;
3410  }
3411  /* this is the best rule so far (ignoring user DST) */
3412  applying_date_diff = date_diff;
3413  applying_ds_rule = curr_ds_rule;
3414  applying_ds_id = curr_ds_id;
3415  applying_is_in_leap_interval = is_in_leap_interval;
3416  if (check_prev_year == false)
3417  {
3418  applying_with_prev_year = true;
3419  }
3420  }
3421  }
3422  else if (curr_ds_rule->from_year < src_year && check_prev_year == true && date_diff < 0)
3423  {
3424  err_status =
3425  tz_get_ds_change_julian_date_diff (src_julian_date, curr_ds_rule, src_year - 1, &ds_rule_julian_date,
3426  &date_diff);
3427  if (err_status != NO_ERROR)
3428  {
3429  goto exit;
3430  }
3431 
3432  assert (date_diff >= 0);
3433  rule_matched = true;
3434  check_prev_year = false;
3435 
3436  goto match_ds_rule;
3437  }
3438  }
3439 
3440  if (applying_ds_id == -1)
3441  {
3442  applying_ds_id = second_best_applying_ds_id;
3443  applying_ds_rule = second_best_applying_ds_rule;
3444  }
3445 
3446  if (applying_ds_id != -1)
3447  {
3448  save_time = applying_ds_rule->save_time;
3449  }
3450  src_offset_curr_off_rule = tz_offset (src_is_utc, curr_off_rule->until_time_type, gmt_std_offset_sec, save_time);
3451  if (prev_off_rule != NULL)
3452  {
3453  src_offset_prev_off_rule = tz_offset (src_is_utc, prev_off_rule->until_time_type, gmt_std_offset_sec, save_time);
3454  }
3455 
3456  if (applying_ds_id != -1)
3457  {
3458  full_date_t offset_rule_diff;
3459  int add_ds_save_time = 0;
3460  full_date_t leap = 0;
3461 
3462  if (FULL_DATE (src_julian_date, src_time_sec + src_offset_curr_off_rule) >=
3463  FULL_DATE (rule_julian_date, rule_time_sec))
3464  {
3466  goto detect_dst;
3467  }
3468 
3469  offset_rule_diff =
3470  FULL_DATE (src_julian_date, src_time_sec + src_offset_prev_off_rule) - FULL_DATE (prev_rule_julian_date,
3471  prev_rule_time_sec);
3472 
3473  if (prev_off_rule != NULL)
3474  {
3475  if (prev_off_rule->until_time_type == TZ_TIME_TYPE_LOCAL_WALL)
3476  {
3477  int prev_rule_save_time = 0;
3478 
3479  add_ds_save_time = save_time;
3480  if (offset_rule_diff <= 2 * SECONDS_IN_A_DAY)
3481  {
3482  err_status = get_saving_time_from_offset_rule (prev_off_rule, tzd, &prev_rule_save_time);
3483  if (err_status != NO_ERROR)
3484  {
3485  goto exit;
3486  }
3487  }
3488  add_ds_save_time -= prev_rule_save_time;
3489  leap = leap_offset_rule_interval + add_ds_save_time;
3490  }
3491  else if (prev_off_rule->until_time_type == TZ_TIME_TYPE_LOCAL_STD)
3492  {
3493  leap = leap_offset_rule_interval;
3494  }
3495  }
3496 
3497  if (try_offset_rule_overlap == false && leap >= 0 && (offset_rule_diff < leap))
3498  {
3499  /* invalid time, abort */
3500  err_status = ER_TZ_DURING_OFFSET_RULE_LEAP;
3501  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3502  goto exit;
3503  }
3504 
3505  if (check_user_dst)
3506  {
3508  (curr_off_rule, applying_ds_rule, tz_info->zone.dst_str, ds_ruleset->default_abrev) == false)
3509  {
3510  if (next_off_rule == NULL || try_offset_rule_overlap == true)
3511  {
3512  err_status = ER_TZ_INVALID_COMBINATION;
3513  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3514  goto exit;
3515  }
3516  /* try the next offset rule to see if we have an ambiguous time */
3517  else
3518  {
3519  try_offset_rule_overlap = true;
3521  goto detect_dst;
3522  }
3523  }
3524  /* we need to see if we have an overlap with the previous rule in this case */
3525  else if (try_offset_rule_overlap == true)
3526  {
3527  bool overlap = false;
3528 
3529  if (ABS (offset_rule_diff) <= 3 * SECONDS_IN_A_DAY)
3530  {
3531  int prev_rule_save_time = 0;
3532  int save_time_diff = 0;
3533 
3534  err_status = get_saving_time_from_offset_rule (prev_off_rule, tzd, &prev_rule_save_time);
3535  if (err_status != NO_ERROR)
3536  {
3537  goto exit;
3538  }
3539 
3540  save_time_diff = save_time - prev_rule_save_time;
3541  overlap =
3542  is_in_overlap_interval (prev_off_rule->until_time_type, offset_rule_diff, leap_offset_rule_interval,
3543  save_time_diff);
3544  }
3545 
3546  if (overlap == false)
3547  {
3548  /* invalid time, abort */
3549  err_status = ER_TZ_INVALID_COMBINATION;
3550  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3551  goto exit;
3552  }
3553  }
3554  }
3555  }
3556  else
3557  {
3558  /* try next GMT offset zone */
3559  if (next_off_rule == NULL
3560  || (FULL_DATE (src_julian_date, src_time_sec + src_offset_curr_off_rule) <
3561  FULL_DATE (rule_julian_date, rule_time_sec)))
3562  {
3563  full_date_t offset_rule_diff;
3564  int add_ds_save_time = 0;
3565  full_date_t leap = 0;
3566 
3567  offset_rule_diff =
3568  FULL_DATE (src_julian_date, src_time_sec + src_offset_prev_off_rule) - FULL_DATE (prev_rule_julian_date,
3569  prev_rule_time_sec);
3570 
3571  if (prev_off_rule != NULL)
3572  {
3573  if (prev_off_rule->until_time_type == TZ_TIME_TYPE_LOCAL_WALL)
3574  {
3575  int prev_rule_save_time = 0;
3576 
3577  add_ds_save_time = save_time;
3578  if (offset_rule_diff <= 2 * SECONDS_IN_A_DAY)
3579  {
3580  err_status = get_saving_time_from_offset_rule (prev_off_rule, tzd, &prev_rule_save_time);
3581  if (err_status != NO_ERROR)
3582  {
3583  goto exit;
3584  }
3585  }
3586  add_ds_save_time -= prev_rule_save_time;
3587  leap = leap_offset_rule_interval + add_ds_save_time;
3588  }
3589  else if (prev_off_rule->until_time_type == TZ_TIME_TYPE_LOCAL_STD)
3590  {
3591  leap = leap_offset_rule_interval;
3592  }
3593  }
3594 
3595  if (try_offset_rule_overlap == false && leap >= 0 && (offset_rule_diff < leap))
3596  {
3597  /* invalid time, abort */
3598  err_status = ER_TZ_DURING_OFFSET_RULE_LEAP;
3599  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3600  goto exit;
3601  }
3602 
3603  if (curr_ds_id == ds_ruleset->count)
3604  {
3605  applying_ds_id = get_closest_ds_rule (src_julian_date, src_time_sec, ds_ruleset, tzd, BACKWARD);
3606  }
3607  else
3608  {
3609  applying_ds_id = get_closest_ds_rule (src_julian_date, src_time_sec, ds_ruleset, tzd, FORWARD);
3610  }
3611 
3612  assert (applying_ds_id + ds_ruleset->index_start < tzd->ds_rule_count);
3613  applying_ds_rule = &(tzd->ds_rules[applying_ds_id + ds_ruleset->index_start]);
3614 
3615  /* check if provided DS specifier matches the offset rule format */
3616  if (tz_info->zone.dst_str[0] != '\0'
3617  && tz_check_ds_match_string (curr_off_rule, applying_ds_rule, tz_info->zone.dst_str,
3618  ds_ruleset->default_abrev) == false)
3619  {
3620  if (next_off_rule == NULL || try_offset_rule_overlap == true)
3621  {
3622  err_status = ER_TZ_INVALID_DST;
3623  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3624  goto exit;
3625  }
3626  else
3627  {
3628  try_offset_rule_overlap = true;
3630  goto detect_dst;
3631  }
3632  }
3633  else if (tz_info->zone.dst_str[0] != '\0'
3634  && tz_check_ds_match_string (curr_off_rule, applying_ds_rule, tz_info->zone.dst_str,
3635  ds_ruleset->default_abrev) == true && try_offset_rule_overlap == true)
3636  {
3637  bool overlap = false;
3638 
3639  if (ABS (offset_rule_diff) <= 3 * SECONDS_IN_A_DAY)
3640  {
3641  int prev_rule_save_time = 0;
3642  int save_time_diff = 0;
3643 
3644  err_status = get_saving_time_from_offset_rule (prev_off_rule, tzd, &prev_rule_save_time);
3645  if (err_status != NO_ERROR)
3646  {
3647  goto exit;
3648  }
3649 
3650  save_time_diff = save_time - prev_rule_save_time;
3651  overlap =
3652  is_in_overlap_interval (prev_off_rule->until_time_type, offset_rule_diff, leap_offset_rule_interval,
3653  save_time_diff);
3654  }
3655  if (overlap == false)
3656  {
3657  /* invalid time, abort */
3658  err_status = ER_TZ_INVALID_COMBINATION;
3659  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
3660  goto exit;
3661  }
3662  }
3663 
3664  goto exit;
3665  }
3667  goto detect_dst;
3668  }
3669 
3670  assert (applying_ds_rule != NULL);
3671 
3672  total_offset_sec += applying_ds_rule->save_time;
3673 
3674  assert (curr_offset_id != -1);
3675  assert (applying_ds_id != -1);
3676 
3677 exit:
3678  if (err_status == NO_ERROR)
3679  {
3680  if (curr_offset_id >= 0)
3681  {
3682  if (curr_off_rule->ds_type == DS_TYPE_FIXED)
3683  {
3684  total_offset_sec += curr_off_rule->ds_ruleset;
3685  }
3686 
3687  tz_info->zone.offset_id = curr_offset_id;
3688 
3689  if (applying_ds_id >= 0)
3690  {
3691  tz_info->zone.dst_id = applying_ds_id;
3692  }
3693  }
3694 
3695  if (only_tz_adjust == true)
3696  {
3697  *dest_dt = *src_dt;
3698  }
3699  else
3700  {
3701  if (src_dt->date == 0)
3702  {
3703  assert (src_dt->time == 0);
3704  *dest_dt = *src_dt;
3705  }
3706  else
3707  {
3708  err_status =
3709  db_add_int_to_datetime ((DB_DATETIME *) src_dt, -1000 * TIME_OFFSET (src_is_utc, total_offset_sec),
3710  dest_dt);
3711  }
3712  }
3713  }
3714 
3715  return err_status;
3716 }
3717 
3718 /*
3719  * tz_conv_tz_datetime_w_zone_info () - Converts a source DATETIME from one timezone to another
3720  *
3721  * Return: error code
3722  * src_dt(in): object containing source datetime value;
3723  * src_zone_info_in(in): (partial) decoded timezone info associated with source datetime
3724  * dest_zone_info_in(in): (partial) decoded timezone info for the desired timezone
3725  * dest_dt(out): destination datetime value
3726  * src_zone_info_out(out): complete timezone information for source
3727  * dest_zone_info_out(out): complete timezone information for destination
3728  */
3729 static int
3730 tz_conv_tz_datetime_w_zone_info (const DB_DATETIME * src_dt, const TZ_DECODE_INFO * src_zone_info_in,
3731  const TZ_DECODE_INFO * dest_zone_info_in, DB_DATETIME * dest_dt,
3732  TZ_DECODE_INFO * src_zone_info_out, TZ_DECODE_INFO * dest_zone_info_out)
3733 {
3734  int err_status = NO_ERROR;
3735  DB_DATETIME dt_utc;
3736  TZ_DECODE_INFO tmp_zone_info;
3737 
3738  assert (src_dt != NULL);
3739  assert (src_zone_info_in != NULL);
3740  assert (dest_zone_info_in != NULL);
3741  assert (dest_dt != NULL);
3742 
3743  tmp_zone_info = *src_zone_info_in;
3744  if (src_zone_info_in->type == TZ_REGION_OFFSET && src_zone_info_in->offset == 0)
3745  {
3746  /* the source is UTC */
3747  dt_utc = *src_dt;
3748  }
3749  else
3750  {
3751  /* convert to UTC */
3752  err_status = tz_datetime_utc_conv (src_dt, &tmp_zone_info, false, false, &dt_utc);
3753  if (err_status != NO_ERROR)
3754  {
3755  goto exit;
3756  }
3757  }
3758 
3759  if (src_zone_info_out != NULL)
3760  {
3761  *src_zone_info_out = tmp_zone_info;
3762  }
3763 
3764  assert (TZ_IS_ZONE_VALID_DECODE_INFO (src_zone_info_in));
3765 
3766  if (src_zone_info_in->type == dest_zone_info_in->type
3767  && ((src_zone_info_in->type == TZ_REGION_ZONE
3768  && src_zone_info_in->zone.zone_id == dest_zone_info_in->zone.zone_id)
3769  || (src_zone_info_in->type == TZ_REGION_OFFSET && src_zone_info_in->offset == dest_zone_info_in->offset)))
3770  {
3771  /* same zone, copy value and zone information */
3772  *dest_dt = *src_dt;
3773  if (dest_zone_info_out != NULL)
3774  {
3775  *dest_zone_info_out = tmp_zone_info;
3776  }
3777  return err_status;
3778  }
3779 
3780  tmp_zone_info = *dest_zone_info_in;
3781  if (dest_zone_info_in->type == TZ_REGION_OFFSET && dest_zone_info_in->offset == 0)
3782  {
3783  /* the destination is UTC */
3784  *dest_dt = dt_utc;
3785  }
3786  else
3787  {
3788  err_status = tz_datetime_utc_conv (&dt_utc, &tmp_zone_info, true, false, dest_dt);
3789  }
3790 
3791  if (dest_zone_info_out != NULL)
3792  {
3793  *dest_zone_info_out = tmp_zone_info;
3794  }
3795 
3796 exit:
3797  return err_status;
3798 }
3799 
3800 /*
3801  * tz_conv_tz_datetime_w_region () - Converts a source DATETIME from one timezone to another (uses region arguments)
3802  *
3803  * Return: error code
3804  * src_dt(in): object containing source datetime value;
3805  * src_tz_region(in): timezone region associated with source datetime
3806  * dest_tz_region(in): desired timezone region
3807  * dest_dt(out): destination datetime value
3808  * src_tz_id_out(out): compressed timezone identifier of the source
3809  * dest_tz_id_out(out): compressed timezone identifier of the destination
3810  */
3811 int
3812 tz_conv_tz_datetime_w_region (const DB_DATETIME * src_dt, const TZ_REGION * src_tz_region,
3813  const TZ_REGION * dest_tz_region, DB_DATETIME * dest_dt, TZ_ID * src_tz_id_out,
3814  TZ_ID * dest_tz_id_out)
3815 {
3816  int err_status = NO_ERROR;
3817  TZ_DECODE_INFO src_zone_info;
3818  TZ_DECODE_INFO dest_zone_info_in;
3819  TZ_DECODE_INFO src_zone_info_out = { TZ_REGION_OFFSET, {0} };
3820  TZ_DECODE_INFO dest_zone_info_out = { TZ_REGION_OFFSET, {0} };
3821 
3822  assert (src_dt != NULL);
3823  assert (src_tz_region != NULL);
3824  assert (dest_tz_region != NULL);
3825  assert (dest_dt != NULL);
3826 
3827  tz_decode_tz_region (src_tz_region, &src_zone_info);
3828  tz_decode_tz_region (dest_tz_region, &dest_zone_info_in);
3829 
3830  err_status =
3831  tz_conv_tz_datetime_w_zone_info (src_dt, &src_zone_info, &dest_zone_info_in, dest_dt, &src_zone_info_out,
3832  &dest_zone_info_out);
3833  if (src_tz_id_out != NULL)
3834  {
3835  tz_encode_tz_id (&src_zone_info_out, src_tz_id_out);
3836  }
3837 
3838  if (dest_tz_id_out != NULL)
3839  {
3840  tz_encode_tz_id (&dest_zone_info_out, dest_tz_id_out);
3841  }
3842 
3843  return err_status;
3844 }
3845 
3846 /*
3847  * tz_conv_tz_datetime_w_zone_name () - Converts a source DATETIME from one timezone to another
3848  *
3849  * Return: error code
3850  * src_dt(in): object containing source datetime value
3851  * source_zone(in): source timezone string
3852  * len_source(in): length of source timezone string
3853  * dest_zone(in): destination timezone string
3854  * len_dest(in): length of destination timezone string
3855  * dest_dt(out): object containing output datetime value
3856  */
3857 int
3858 tz_conv_tz_datetime_w_zone_name (const DB_DATETIME * src_dt, const char *source_zone, int len_source,
3859  const char *dest_zone, int len_dest, DB_DATETIME * dest_dt)
3860 {
3861  int err_status;
3862  TZ_REGION source, dest;
3863 
3864  err_status = tz_str_to_region (source_zone, len_source, &source);
3865  if (err_status != NO_ERROR)
3866  {
3867  return err_status;
3868  }
3869 
3870  err_status = tz_str_to_region (dest_zone, len_dest, &dest);
3871  if (err_status != NO_ERROR)
3872  {
3873  return err_status;
3874  }
3875 
3876  return tz_conv_tz_datetime_w_region (src_dt, &source, &dest, dest_dt, NULL, NULL);
3877 }
3878 
3879 /*
3880  * tz_explain_tz_id () - get timezone information
3881  *
3882  * Return: print characters
3883  * tz_id(in): complete valid zone identifier
3884  * tzr(out): buffer string for timezone region info
3885  * tzr_size(in): size of tz_str
3886  * tzdst(out): buffer string for daylight saving time info
3887  * tzdst_size (in) : size of tzdst
3888  * tzh(out): time zone hour offset
3889  * tzm(out): time zone minute offset
3890  * Return: error or no error
3891  */
3892 int
3893 tz_explain_tz_id (const TZ_ID * tz_id, char *tzr, const int tzr_size, char *tzdst, const int tzdst_size, int *tzh,
3894  int *tzm)
3895 {
3896 #define LEN_MIN_HOUR 6
3897 #define LEN_MIN_HOUR_SEC 9
3898  const TZ_DATA *tzd = tz_get_data ();
3899  int zone_name_size;
3900  int zone_id;
3901  int zone_offset_id;
3902  int dst_format_size;
3903  TZ_TIMEZONE *timezone = NULL;
3904  TZ_OFFSET_RULE *zone_off_rule;
3905  TZ_DECODE_INFO tz_info;
3906  char dst_format[TZ_MAX_FORMAT_SIZE];
3907  const char *p_dst_format = NULL;
3908  int total_offset = 0;
3909  int er_status = NO_ERROR;
3910 
3911  tz_decode_tz_id (tz_id, true, &tz_info);
3912  if (tz_info.type == TZ_REGION_OFFSET)
3913  {
3914  int offset = tz_info.offset;
3915  int hour, min, sec;
3916  char sign;
3917 
3918  if (tz_info.offset == TZ_INVALID_OFFSET)
3919  {
3920 #if !defined (CS_MODE)
3922 #endif
3923  er_status = ER_TZ_INTERNAL_ERROR;
3924  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, er_status, 0);
3925  return er_status;
3926  }
3927 
3928  sign = (tz_info.offset < 0) ? '-' : '+';
3929 
3930  if (offset < TZ_MIN_OFFSET || offset > TZ_MAX_OFFSET)
3931  {
3932  er_status = ER_DATE_CONVERSION;
3933  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, er_status, 0);
3934  return er_status;
3935  }
3936 
3937  offset = (offset < 0) ? (-offset) : offset;
3938  db_time_decode ((DB_TIME *) (&offset), &hour, &min, &sec);
3939 
3940  *tzh = hour;
3941  *tzm = min;
3942  if (sign == '-')
3943  {
3944  *tzh = -(*tzh);
3945  *tzm = -(*tzm);
3946  }
3947 
3948  if (sec > 0)
3949  {
3950  sprintf (tzr, "%c%02d:%02d:%02d", sign, hour, min, sec);
3951  tzr[LEN_MIN_HOUR_SEC] = '\0';
3952  }
3953  else
3954  {
3955  sprintf (tzr, "%c%02d:%02d", sign, hour, min);
3956  tzr[LEN_MIN_HOUR] = '\0';
3957  }
3958  return er_status;
3959  }
3960 
3961  if (tzd == NULL)
3962  {
3963  er_status = ER_TZ_LOAD_ERROR;
3964  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, er_status, 1, "timezone lib not loaded");
3965  return er_status;
3966  }
3967 
3968  assert (tz_info.zone.p_zone_off_rule != NULL);
3969  total_offset = tz_info.zone.p_zone_off_rule->gmt_off;
3970  if (tz_info.zone.p_zone_off_rule->ds_type == DS_TYPE_RULESET_ID && tz_info.zone.p_ds_rule != NULL)
3971  {
3972  total_offset += tz_info.zone.p_ds_rule->save_time;
3973  }
3974  *tzh = total_offset / 3600;
3975  *tzm = (total_offset % 3600) / 60;
3976  zone_id = tz_info.zone.zone_id;
3977  zone_offset_id = tz_info.zone.offset_id;
3978  zone_name_size = strlen (tzd->names[zone_id].name);
3979 
3980  timezone = &(tzd->timezones[tzd->names[zone_id].zone_id]);
3981  zone_off_rule = &(tzd->offset_rules[timezone->gmt_off_rule_start + zone_offset_id]);
3982 
3983  p_dst_format = zone_off_rule->std_format;
3984  if (zone_off_rule->ds_type == DS_TYPE_RULESET_ID)
3985  {
3986  TZ_DS_RULESET *ds_ruleset = NULL;
3987  TZ_DS_RULE *ds_rule = NULL;
3988  int dst_id = tz_info.zone.dst_id;
3989  const char *ds_abbr = NULL;
3990 
3991  ds_ruleset = &(tzd->ds_rulesets[zone_off_rule->ds_ruleset]);
3992  if (dst_id < ds_ruleset->count)
3993  {
3994  ds_rule = &(tzd->ds_rules[dst_id + ds_ruleset->index_start]);
3995  ds_abbr = ds_rule->letter_abbrev;
3996  }
3997 
3998  if (zone_off_rule->var_format != NULL)
3999  {
4000  if (ds_abbr == NULL)
4001  {
4002  p_dst_format = NULL;
4003  }
4004  else
4005  {
4006  snprintf (dst_format, sizeof (dst_format) - 1, zone_off_rule->var_format,
4007  (ds_abbr != NULL && *ds_abbr != '-') ? ds_abbr : "");
4008  p_dst_format = dst_format;
4009  }
4010  }
4011  else
4012  {
4013  if (ds_rule != NULL && ds_rule->save_time != 0 && zone_off_rule->save_format != NULL)
4014  {
4015  p_dst_format = zone_off_rule->save_format;
4016  }
4017  }
4018  }
4019 
4020  if (p_dst_format != NULL)
4021  {
4022  dst_format_size = strlen (p_dst_format);
4023  }
4024  else
4025  {
4026  dst_format_size = 0;
4027  }
4028 
4029  if (zone_name_size + 1 > tzr_size || dst_format_size + 1 > tzdst_size)
4030  {
4031  er_status = ER_FAILED;
4032  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, er_status, 0);
4033  return er_status;
4034  }
4035 
4036  if (p_dst_format != NULL)
4037  {
4038  snprintf (tzr, tzr_size, "%s", tzd->names[zone_id].name);
4039  snprintf (tzdst, tzdst_size, "%s", p_dst_format);
4040  tzdst[dst_format_size] = '\0';
4041  }
4042  else
4043  {
4044  snprintf (tzr, tzr_size, "%s", tzd->names[zone_id].name);
4045  }
4046 
4047  tzr[zone_name_size] = '\0';
4048 
4049  return er_status;
4050 #undef LEN_MIN_HOUR
4051 #undef LEN_MIN_HOUR_SEC
4052 }
4053 
4054 /*
4055  * tz_create_datetimetz_from_offset () - creates a datetime with timezone info from a timezone hour offset and a
4056  * a timezone minute offset
4057  *
4058  *
4059  * Return: error or no error
4060  * dt (in): local datetime value
4061  * tzh (in): timezone hour offset
4062  * tzm (in): timezone minute offset
4063  * dt_tz (out): object containing datetime value (adjusted to UTC) and
4064  * timezone info
4065  *
4066  */
4067 int
4068 tz_create_datetimetz_from_offset (const DB_DATETIME * dt, const int tzh, const int tzm, DB_DATETIMETZ * dt_tz)
4069 {
4070  int err_status = NO_ERROR;
4071  DB_DATETIME utc_dt;
4072  TZ_DECODE_INFO tz_info;
4073 
4074  tz_info.type = TZ_REGION_OFFSET;
4075  tz_info.offset = tzh * 3600 + tzm * 60;
4076 
4077  if (tz_info.offset < TZ_MIN_OFFSET || tz_info.offset > TZ_MAX_OFFSET)
4078  {
4080  err_status = ER_DATE_CONVERSION;
4081  return err_status;
4082  }
4083 
4084  err_status = tz_datetime_utc_conv (dt, &tz_info, false, false, &utc_dt);
4085  if (err_status != NO_ERROR)
4086  {
4087  return err_status;
4088  }
4089  tz_encode_tz_id (&tz_info, &(dt_tz->tz_id));
4090  dt_tz->datetime = utc_dt;
4091  return err_status;
4092 }
4093 
4094 /*
4095  * tz_create_timestamptz_from_offset () - creates a timestamp with timezone info from a timezone hour and
4096  * a timezone minute offset
4097  *
4098  * Return: error code
4099  * date(in): local date value
4100  * time(in): local time value
4101  * tzh(in): timezone hour offset
4102  * tzm(in): timezone minute offset
4103  * timestamp_tz(out): object containing timestamp value (adjusted to UTC) and timezone info
4104  *
4105  */
4106 int
4107 tz_create_timestamptz_from_offset (const DB_DATE * date, const DB_TIME * time, const int tzh, const int tzm,
4108  DB_TIMESTAMPTZ * timestamp_tz)
4109 {
4110  int err_status = NO_ERROR;
4111  DB_DATETIME dt, utc_dt;
4112  TZ_DECODE_INFO tz_info;
4113  DB_DATE date_utc;
4114  DB_TIME time_utc;
4115 
4116  tz_info.type = TZ_REGION_OFFSET;
4117  tz_info.offset = tzh * 3600 + tzm * 60;
4118 
4119  if (tz_info.offset < TZ_MIN_OFFSET || tz_info.offset > TZ_MAX_OFFSET)
4120  {
4122  err_status = ER_DATE_CONVERSION;
4123  return err_status;
4124  }
4125 
4126  dt.date = *date;
4127  dt.time = (*time) * 1000;
4128 
4129  err_status = tz_datetime_utc_conv (&dt, &tz_info, false, false, &utc_dt);
4130  if (err_status != NO_ERROR)
4131  {
4132  goto exit;
4133  }
4134  date_utc = utc_dt.date;
4135  time_utc = utc_dt.time / 1000;
4136 
4137  err_status = db_timestamp_encode_utc (&date_utc, &time_utc, &timestamp_tz->timestamp);
4138  if (err_status != NO_ERROR)
4139  {
4140  goto exit;
4141  }
4142  tz_encode_tz_id (&tz_info, &(timestamp_tz->tz_id));
4143 
4144 exit:
4145  return err_status;
4146 }
4147 
4148 /*
4149  * tz_get_best_match_zone() - searches for the longest timezone matching the start of the string
4150  *
4151  * Returns: matched zone id (negative if not matched)
4152  * name(in): string (null terminated)
4153  * size(out): matched size
4154  *
4155  */
4156 int
4157 tz_get_best_match_zone (const char *name, int *size)
4158 {
4159  const TZ_DATA *tzd;
4160  int index_bot, index_top;
4161  int cmp_res;
4162 
4163  assert (name != NULL);
4164 
4165  tzd = tz_get_data ();
4166  if (tzd == NULL)
4167  {
4168  return -1;
4169  }
4170 
4171  index_bot = 0;
4172  index_top = tzd->name_count - 1;
4173 
4174  while (index_bot <= index_top)
4175  {
4176  int mid = index_bot + ((index_top - index_bot) >> 1);
4177  cmp_res = starts_with (tzd->names[mid].name, name);
4178 
4179  if (cmp_res <= 0)
4180  {
4181  index_bot = mid + 1;
4182  }
4183  else
4184  {
4185  index_top = mid - 1;
4186  }
4187  }
4188 
4189  if (index_bot == 0 || starts_with (tzd->names[index_bot - 1].name, name) != 0)
4190  {
4191  return -1;
4192  }
4193 
4194  *size = strlen (tzd->names[index_bot - 1].name);
4195  return index_bot - 1;
4196 }
4197 
4198 /*
4199  * tz_create_datetimetz_from_zoneid_and_tzd () - creates a datetime with timezone info from a datetime, a zone id
4200  * and daylight saving time info
4201  *
4202  *
4203  * Return: error or no error
4204  * dt(in): local datetime value
4205  * default_tz_region(in): default timezone region (used when zone_id is invalid)
4206  * zone_id(in): the zone id
4207  * tzd(in): daylight saving time info string
4208  * tzd_len(in): length of the tzd string
4209  * dt_tz(out): object containing datetime value(adjusted to UTC) and timezone info
4210  */
4211 int
4212 tz_create_datetimetz_from_zoneid_and_tzd (const DB_DATETIME * dt, TZ_REGION * default_tz_region, const int zone_id,
4213  const char *tzd, const int tzd_len, bool is_time_tz, DB_DATETIMETZ * dt_tz)
4214 {
4215  int err_status = NO_ERROR;
4216  DB_DATETIME utc_dt;
4217  TZ_DECODE_INFO tz_info;
4218  int offset = 0;
4219 
4220  if (zone_id != -1)
4221  {
4222  tz_info.type = TZ_REGION_ZONE;
4223  tz_info.zone.zone_id = zone_id;
4224  tz_info.zone.dst_id = TZ_DS_ID_MAX;
4225  tz_info.zone.offset_id = TZ_OFFSET_ID_MAX;
4226  }
4227  else
4228  {
4229  tz_decode_tz_region (default_tz_region, &tz_info);
4230  }
4231 
4232  if (tzd != NULL)
4233  {
4234  if (tzd_len + 1 > (int) sizeof (tz_info.zone.dst_str))
4235  {
4237  return ER_TZ_INVALID_DST;
4238  }
4239  strncpy (tz_info.zone.dst_str, tzd, tzd_len);
4240  tz_info.zone.dst_str[tzd_len] = '\0';
4241  }
4242  else
4243  {
4244  tz_info.zone.dst_str[0] = '\0';
4245  }
4246 
4247  err_status = tz_datetime_utc_conv (dt, &tz_info, false, false, &utc_dt);
4248  if (err_status != NO_ERROR)
4249  {
4250  return err_status;
4251  }
4252 
4253  if (is_time_tz == true)
4254  {
4255  offset = (int) (dt->date - utc_dt.date) * 3600 * 24 + (int) (dt->time - utc_dt.time) / 1000;
4256  tz_info.type = TZ_REGION_OFFSET;
4257  tz_info.offset = offset;
4258  }
4259 
4260  tz_encode_tz_id (&tz_info, &(dt_tz->tz_id));
4261  dt_tz->datetime = utc_dt;
4262 
4263  return err_status;
4264 }
4265 
4266 /*
4267  * tz_create_timestamptz_from_zoneid_and_tzd () - creates a timestamp with timezone info from a datetime, a zone id
4268  * and daylight saving time info
4269  *
4270  * Return: error or no error
4271  * date(in): local date value
4272  * time(in): local time value
4273  * default_tz_region(in): default timezone region (used when zone_id is invalid)
4274  * zone_id(in): the zone id
4275  * tzd(in): daylight saving time info string
4276  * tzd_len(in): length of the tzd string
4277  * timestamp_tz(out): object containing timestamp value(adjusted to UTC) and timezone info
4278  */
4279 int
4280 tz_create_timestamptz_from_zoneid_and_tzd (const DB_DATE * date, const DB_TIME * time, TZ_REGION * default_tz_region,
4281  const int zone_id, const char *tzd, const int tzd_len,
4282  DB_TIMESTAMPTZ * timestamp_tz)
4283 {
4284  int err_status = NO_ERROR;
4285  DB_DATETIME utc_dt, dt;
4286  TZ_DECODE_INFO tz_info;
4287  DB_DATE date_utc;
4288  DB_TIME time_utc;
4289 
4290  if (zone_id != -1)
4291  {
4292  tz_info.type = TZ_REGION_ZONE;
4293  tz_info.zone.zone_id = zone_id;
4294  tz_info.zone.dst_id = TZ_DS_ID_MAX;
4295  tz_info.zone.offset_id = TZ_OFFSET_ID_MAX;
4296  }
4297  else
4298  {
4299  tz_decode_tz_region (default_tz_region, &tz_info);
4300  }
4301 
4302  if (tzd != NULL)
4303  {
4304  if (tzd_len + 1 > (int) sizeof (tz_info.zone.dst_str))
4305  {
4307  return ER_TZ_INVALID_DST;
4308  }
4309  strncpy (tz_info.zone.dst_str, tzd, tzd_len);
4310  tz_info.zone.dst_str[tzd_len] = '\0';
4311  }
4312  else
4313  {
4314  tz_info.zone.dst_str[0] = '\0';
4315  }
4316 
4317  dt.date = *date;
4318  dt.time = *(time) * 1000;
4319  err_status = tz_datetime_utc_conv (&dt, &tz_info, false, false, &utc_dt);
4320 
4321  if (err_status != NO_ERROR)
4322  {
4323  return err_status;
4324  }
4325 
4326  date_utc = utc_dt.date;
4327  time_utc = utc_dt.time / 1000;
4328  err_status = db_timestamp_encode_utc (&date_utc, &time_utc, &(timestamp_tz->timestamp));
4329  if (err_status != NO_ERROR)
4330  {
4331  return err_status;
4332  }
4333 
4334  tz_encode_tz_id (&tz_info, &(timestamp_tz->tz_id));
4335  return err_status;
4336 }
4337 
4338 /*
4339  * starts_with() - verifies if prefix is a prefix of str
4340  * otherwise, verifies if prefix is lexicographically greater or smaller than str
4341  * Return 0 if prefix is a prefix of str
4342  * Return > 0 if prefix is lexicographically greater than str
4343  * Return < 0 if prefix is lexicographically smaller than str
4344  * prefix(in): the prefix string
4345  * str(in): the string to search for the prefix
4346  *
4347  */
4348 static int
4349 starts_with (const char *prefix, const char *str)
4350 {
4351  while (*prefix != '\0' && (*prefix) == (*str))
4352  {
4353  prefix++, str++;
4354  }
4355  if (*prefix == '\0')
4356  {
4357  return 0;
4358  }
4359 
4360  return *(const unsigned char *) prefix - *(const unsigned char *) str;
4361 }
4362 
4363 #if defined(LINUX)
4364 /*
4365  * find_timezone_from_clock() - Tries to put in timezone_name the local timezone taken from /etc/sysconfig/clock
4366  * Return >= 0 if no error
4367  * Return < 0 if error
4368  * timezone_name(out): the local timezone
4369  * buf_len(in): number of elements in the buffer without the null ending
4370  * character
4371  */
4372 static int
4373 find_timezone_from_clock (char *timezone_name, int buf_len)
4374 {
4375 #define MAX_LINE_SIZE 256
4376  int cnt = 0;
4377  FILE *fp;
4378  char str[MAX_LINE_SIZE + 1];
4379  char *zone = NULL;
4380 
4381  fp = fopen ("/etc/sysconfig/clock", "r");
4382  if (fp == NULL)
4383  {
4384  return -1;
4385  }
4386 
4387  while (fgets (str, MAX_LINE_SIZE + 1, fp) != NULL)
4388  {
4389  if (*str == '#')
4390  {
4391  continue;
4392  }
4393  if (cnt == 0)
4394  {
4395  zone = strstr (str, "ZONE");
4396  if (zone != NULL)
4397  {
4398  zone += 4;
4399  while (*zone == ' ')
4400  {
4401  zone++;
4402  }
4403 
4404  if (*zone != '=')
4405  {
4406  goto error;
4407  }
4408 
4409  zone++;
4410  while (*zone == ' ')
4411  {
4412  zone++;
4413  }
4414 
4415  if (*zone != '"')
4416  {
4417  goto error;
4418  }
4419 
4420  zone++;
4421  while (*zone != '"' && *zone != '\0')
4422  {
4423  timezone_name[cnt++] = *zone;
4424  zone++;
4425  if (cnt > buf_len)
4426  {
4427  goto error;
4428  }
4429  }
4430  if (*zone == '"')
4431  {
4432  break;
4433  }
4434  }
4435  }
4436  else
4437  {
4438  zone = str;
4439  while (*zone != '"' && *zone != '\0')
4440  {
4441  timezone_name[cnt++] = *zone;
4442  zone++;
4443  if (cnt > buf_len)
4444  {
4445  goto error;
4446  }
4447  }
4448  break;
4449  }
4450  }
4451 
4452  timezone_name[cnt] = '\0';
4453  fclose (fp);
4454  return 0;
4455 
4456 error:
4457  fclose (fp);
4458  return -1;
4459 #undef MAX_LINE_SIZE
4460 }
4461 
4462 /*
4463  * find_timezone_from_localtime() - Tries to put in timezona_name the local timezone taken from /etc/localtime
4464  * Return >= 0 if no error
4465  * Return < 0 if error
4466  * timezone_name(out): the local timezone
4467  * buf_len(in): number of elements in the buffer without the null ending
4468  * character
4469  */
4470 static int
4471 find_timezone_from_localtime (char *timezone_name, int buf_len)
4472 {
4473  char linkname[PATH_MAX + 1];
4474  char *p;
4475  const char *zone_info = "zoneinfo";
4476  bool start = false;
4477  ssize_t r;
4478  int cnt = 0;
4479 
4480  memset (linkname, 0, sizeof (linkname));
4481  r = readlink ("/etc/localtime", linkname, PATH_MAX + 1);
4482  if (r < 0)
4483  {
4484  return r;
4485  }
4486 
4487  if (r > PATH_MAX)
4488  {
4489  return -1;
4490  }
4491 
4492  p = strtok (linkname, "/");
4493  while (p != NULL)
4494  {
4495  if (!start)
4496  {
4497  if (strcmp (p, zone_info) == 0)
4498  {
4499  start = true;
4500  }
4501  }
4502  else
4503  {
4504  while (*p != '\0')
4505  {
4506  if (cnt > buf_len)
4507  {
4508  goto error;
4509  }
4510  timezone_name[cnt++] = *p;
4511  p++;
4512  }
4513  if (cnt > buf_len)
4514  {
4515  goto error;
4516  }
4517  timezone_name[cnt++] = '/';
4518  }
4519  p = strtok (NULL, "/");
4520  }
4521 
4522  timezone_name[cnt - 1] = '\0';
4523  return 0;
4524 
4525 error:
4526  return -1;
4527 }
4528 #endif
4529 
4530 #if defined(WINDOWS)
4531 /*
4532  * tz_get_iana_zone_id_by_windows_zone() - returns the ID of the leftmost timezone corresponding to the specified
4533  * windows zone name
4534  *
4535  * Returns: ID of zone, or -1 if not found
4536  * windows_zone_name(in): windows zone name to search for (null-terminated)
4537  */
4538 static int
4539 tz_get_iana_zone_id_by_windows_zone (const char *windows_zone_name)
4540 {
4541  const TZ_DATA *tzd;
4542  int mid = 0;
4543  int index_bot, index_top;
4544  int cmp_res;
4545 
4546  assert (windows_zone_name != NULL);
4547 
4548  tzd = tz_get_data ();
4549  if (tzd == NULL)
4550  {
4551  return -1;
4552  }
4553 
4554  index_bot = 0;
4555  index_top = tzd->windows_iana_map_count - 1;
4556 
4557  while (index_bot <= index_top)
4558  {
4559  mid = index_bot + ((index_top - index_bot) >> 1);
4560  cmp_res = strcmp (windows_zone_name, tzd->windows_iana_map[mid].windows_zone);
4561 
4562  if (cmp_res <= 0)
4563  {
4564  index_top = mid - 1;
4565  }
4566  else
4567  {
4568  index_bot = mid + 1;
4569  }
4570  }
4571 
4572  if (strcmp (tzd->windows_iana_map[index_bot].windows_zone, windows_zone_name) != 0)
4573  {
4574  return -1;
4575  }
4576  return tzd->windows_iana_map[index_bot].iana_zone_id;
4577 }
4578 #endif
4579 
4580 /*
4581  * resolve_timezone() - Puts in timezone the local timezone
4582  * Return >= 0 if no error
4583  * Return < 0 if error
4584  * timezone(out): the local timezone
4585  * buf_len(in): number of elements in the buffer without the null ending character
4586  */
4587 int
4588 tz_resolve_os_timezone (char *timezone, int buf_len)
4589 {
4590 #if defined (WINDOWS)
4591  const TZ_DATA *tz_data;
4592  int len_iana_zone, iana_zone_id;
4593  char tzname[64];
4594  size_t tzret;
4595 
4596  tz_data = tz_get_data ();
4597  tzset ();
4598  _get_tzname (&tzret, tzname, sizeof (tzname), 0);
4599  iana_zone_id = tz_get_iana_zone_id_by_windows_zone (tzname);
4600  if (iana_zone_id < 0)
4601  {
4602  return iana_zone_id;
4603  }
4604  len_iana_zone = strlen (tz_data->timezone_names[iana_zone_id]);
4605  if (buf_len < len_iana_zone)
4606  {
4607  return -1;
4608  }
4609  memmove (timezone, tz_data->timezone_names[iana_zone_id], len_iana_zone);
4610  timezone[len_iana_zone] = '\0';
4611  return 0;
4612 #elif defined(AIX)
4613  char *env = NULL;
4614  int ret = 0;
4615 
4616  env = getenv ("TZ");
4617  if (env == NULL)
4618  {
4619  return -1;
4620  }
4621  else
4622  {
4623  strncpy (timezone, env, buf_len);
4624  timezone[buf_len] = '\0';
4625  }
4626  ret = tz_get_zone_id_by_name (timezone, strlen (timezone));
4627  return ret;
4628 #else
4629  int ret = 0;
4630 
4631  ret = find_timezone_from_clock (timezone, buf_len);
4632  if (ret < 0)
4633  {
4634  ret = find_timezone_from_localtime (timezone, buf_len);
4635  }
4636  if (ret >= 0)
4637  {
4638  ret = tz_get_zone_id_by_name (timezone, strlen (timezone));
4639  }
4640  return ret;
4641 #endif
4642 }
4643 
4644 /*
4645  * tz_set_tz_region_system() - set a reference to the global tz_region_system variable
4646  *
4647  * Returns: reference to the tz_region_system variable
4648  */
4649 void
4651 {
4652  tz_Region_system = *tz_region;
4653 }
4654 
4655 /*
4656  * tz_get_client_tz_region_session() - get a reference to the global tz_Region_session variable
4657  *
4658  * Returns: reference to the tz_Region_session variable
4659  */
4660 #if !defined(SERVER_MODE)
4661 TZ_REGION *
4663 {
4664  return &tz_Region_session;
4665 }
4666 #endif
4667 
4668 /*
4669  * tz_get_server_tz_region_session() - get a reference to the session TZ_REGION
4670  *
4671  * Returns: reference to the session TZ_REGION variable
4672  */
4673 #if defined(SERVER_MODE)
4674 TZ_REGION *
4675 tz_get_server_tz_region_session (void)
4676 {
4677  THREAD_ENTRY *thread_p;
4678  THREAD_ENTRY *worker_thread_p;
4679  TZ_REGION *session_tz_region;
4680 
4681  thread_p = thread_get_thread_entry_info ();
4682  session_tz_region = session_get_session_tz_region (thread_p);
4683 
4684  if (session_tz_region == NULL)
4685  {
4686  if (thread_p->emulate_tid != thread_id_t ())
4687  {
4688  worker_thread_p = thread_get_manager ()->find_by_tid (thread_p->emulate_tid);
4689  if (worker_thread_p != NULL)
4690  {
4691  session_tz_region = session_get_session_tz_region (worker_thread_p);
4692  }
4693  }
4694  else if (thread_p->type == TT_VACUUM_WORKER)
4695  {
4696  /* just use system region */
4697  session_tz_region = &tz_Region_system;
4698  }
4699  }
4700 
4701  return session_tz_region;
4702 }
4703 #endif
4704 
4705 #if !defined (CS_MODE)
4706 /*
4707  * tz_timezones_start_scan() - start scan function for 'SHOW TIMEZONES'
4708  * return: NO_ERROR, or ER_code
4709  * thread_p(in): thread entry
4710  * show_type(in):
4711  * arg_values(in):
4712  * arg_cnt(in):
4713  * ptr(in/out): 'show timezones' context
4714  */
4715 int
4716 tz_timezones_start_scan (THREAD_ENTRY * thread_p, int show_type, DB_VALUE ** arg_values, int arg_cnt, void **ptr)
4717 {
4718  int error = NO_ERROR;
4720  DB_VALUE *vals = NULL;
4721  const int col_num = 1;
4722  const TZ_DATA *tzd;
4723  int i;
4724 
4725  tzd = tz_get_data ();
4726  if (tzd == NULL)
4727  {
4728  /* no timezones, just return */
4729  return error;
4730  }
4731 
4732  *ptr = NULL;
4733 
4734  ctx = showstmt_alloc_array_context (thread_p, tzd->name_count, col_num);
4735  if (ctx == NULL)
4736  {
4737  error = er_errid ();
4738  return error;
4739  }
4740 
4741  for (i = 0; i < tzd->name_count; i++)
4742  {
4743  vals = showstmt_alloc_tuple_in_context (thread_p, ctx);
4744  if (vals == NULL)
4745  {
4746  error = er_errid ();
4747  goto exit_on_error;
4748  }
4749  /* Geographic timezone name */
4750  db_make_string (&vals[0], tzd->names[i].name);
4751  }
4752 
4753  *ptr = ctx;
4754  return NO_ERROR;
4755 
4756 exit_on_error:
4757  if (ctx != NULL)
4758  {
4759  showstmt_free_array_context (thread_p, ctx);
4760  }
4761 
4762  return error;
4763 }
4764 
4765 /*
4766  * tz_full_timezones_start_scan() - start scan function for 'SHOW FULL TIMEZONES'
4767  * return: NO_ERROR, or ER_code
4768  * thread_p(in): thread entry
4769  * show_type(in):
4770  * arg_values(in):
4771  * arg_cnt(in):
4772  * ptr(in/out): 'show timezones' context
4773  */
4774 int
4775 tz_full_timezones_start_scan (THREAD_ENTRY * thread_p, int show_type, DB_VALUE ** arg_values, int arg_cnt, void **ptr)
4776 {
4777  int error = NO_ERROR;
4779  DB_VALUE *vals = NULL;
4780  const int col_num = 4;
4781  const TZ_DATA *tzd;
4782  int i;
4783  time_t cur_time;
4784  DB_DATETIME utc_datetime, dummy_datetime;
4785  int year, month, day, hour, minute, second;
4786  TZ_DECODE_INFO tzinfo;
4787  TZ_TIMEZONE timezone;
4788  TZ_OFFSET_RULE zone_off_rule;
4789  char dst_format[TZ_MAX_FORMAT_SIZE];
4790  const char *dst_name = NULL;
4791  char gmt_offset[MAX_LEN_OFFSET];
4792  char dst_offset[MAX_LEN_OFFSET];
4793  char empty_string[1];
4794 
4795  empty_string[0] = '\0';
4796  tzd = tz_get_data ();
4797  if (tzd == NULL)
4798  {
4799  /* no timezones, just return */
4800  return error;
4801  }
4802 
4803  *ptr = NULL;
4804 
4805  ctx = showstmt_alloc_array_context (thread_p, tzd->name_count, col_num);
4806  if (ctx == NULL)
4807  {
4808  error = er_errid ();
4809  return error;
4810  }
4811 
4812  /* Get the current time in seconds */
4813  time (&cur_time);
4814  tz_timestamp_decode_no_leap_sec ((int) cur_time, &year, &month, &day, &hour, &minute, &second);
4815 
4816  error = db_datetime_encode (&utc_datetime, month + 1, day, year, hour, minute, second, 0);
4817  if (error != NO_ERROR)
4818  {
4819  goto exit_on_error;
4820  }
4821 
4822  for (i = 0; i < tzd->name_count; i++)
4823  {
4824  int idx = 0;
4825  int dst_save_time = 0;
4826  int zone_id;
4827 
4828  vals = showstmt_alloc_tuple_in_context (thread_p, ctx);
4829  if (vals == NULL)
4830  {
4831  error = er_errid ();
4832  goto exit_on_error;
4833  }
4834  /* Geographic timezone name */
4835  db_make_string (&vals[idx++], tzd->names[i].name);
4836 
4837  /* First get the zone id */
4838  zone_id = i;
4839 
4840  tzinfo.type = TZ_REGION_ZONE;
4841  tzinfo.zone.zone_id = zone_id;
4842  tzinfo.zone.dst_str[0] = '\0';
4843 
4844  error = tz_datetime_utc_conv (&utc_datetime, &tzinfo, true, true, &dummy_datetime);
4845  if (error != NO_ERROR)
4846  {
4847  goto exit_on_error;
4848  }
4849 
4850  timezone = tzd->timezones[tzd->names[i].zone_id];
4851  zone_off_rule = tzd->offset_rules[timezone.gmt_off_rule_start + tzinfo.zone.offset_id];
4852 
4853  /* Timezone offset */
4854  error = tz_print_tz_offset (gmt_offset, zone_off_rule.gmt_off);
4855  if (error != NO_ERROR)
4856  {
4857  goto exit_on_error;
4858  }
4859  db_make_string_copy (&vals[idx++], gmt_offset);
4860 
4861  dst_name = zone_off_rule.std_format;
4862  if (zone_off_rule.ds_type == DS_TYPE_RULESET_ID)
4863  {
4864  TZ_DS_RULESET ds_ruleset;
4865  TZ_DS_RULE ds_rule;
4866  int dst_id;
4867  const char *ds_abbr = NULL;
4868 
4869  ds_ruleset = tzd->ds_rulesets[zone_off_rule.ds_ruleset];
4870  dst_id = tzinfo.zone.dst_id;
4871 
4872  if (dst_id != TZ_DS_ID_MAX)
4873  {
4874  ds_rule = tzd->ds_rules[dst_id + ds_ruleset.index_start];
4875  dst_save_time = ds_rule.save_time;
4876  ds_abbr = ds_rule.letter_abbrev;
4877 
4878  if (zone_off_rule.var_format != NULL)
4879  {
4880  snprintf (dst_format, sizeof (dst_format) - 1, zone_off_rule.var_format,
4881  (ds_abbr != NULL && *ds_abbr != '-') ? ds_abbr : "");
4882  dst_name = dst_format;
4883  }
4884  else
4885  {
4886  if (dst_save_time != 0)
4887  {
4888  dst_name = zone_off_rule.save_format;
4889  }
4890  }
4891  if (dst_name == NULL)
4892  {
4893  dst_name = empty_string;
4894  }
4895  }
4896  }
4897 
4898  /* Now put the daylight saving time offset and name */
4899  if (dst_name != NULL)
4900  {
4901  error = tz_print_tz_offset (dst_offset, dst_save_time);
4902  if (error != NO_ERROR)
4903  {
4904  goto exit_on_error;
4905  }
4906  db_make_string_copy (&vals[idx++], dst_offset);
4907  db_make_string_copy (&vals[idx++], dst_name);
4908  }
4909  else
4910  {
4911  db_make_null (&vals[idx++]);
4912  db_make_null (&vals[idx++]);
4913  }
4914  }
4915 
4916  *ptr = ctx;
4917  return NO_ERROR;
4918 
4919 exit_on_error:
4920  if (ctx != NULL)
4921  {
4922  showstmt_free_array_context (thread_p, ctx);
4923  }
4924 
4925  return error;
4926 }
4927 #endif
4928 
4929 /*
4930  * tz_load_with_library_path() - opens the timezone library and loads the data into the tzd
4931  * parameter using the given library path
4932  * tzd(in/out) : timezone data
4933  * timezone_library_path(in) : path to timezone library
4934  * Returns: 0 (NO_ERROR) if success, -1 otherwise
4935  */
4936 int
4937 tz_load_with_library_path (TZ_DATA * tzd, const char *timezone_library_path)
4938 {
4939  int err_status = NO_ERROR;
4940  void *tz_Lib_handle = NULL;
4941 
4942  err_status = tz_load_library (timezone_library_path, &tz_Lib_handle);
4943  if (err_status != NO_ERROR)
4944  {
4945  goto error_exit;
4946  }
4947 
4948  err_status = tz_load_data_from_lib (tzd, tz_Lib_handle);
4949  if (err_status != NO_ERROR)
4950  {
4951  goto error_exit;
4952  }
4953 
4954  return NO_ERROR;
4955 
4956 error_exit:
4957  assert (er_errid () != NO_ERROR);
4958 
4959  if (er_errid () == NO_ERROR)
4960  {
4961  err_status = ER_TZ_LOAD_ERROR;
4962  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_TZ_LOAD_ERROR, 1, timezone_library_path);
4963  }
4964 
4965  return err_status;
4966 }
4967 
4968 /*
4969  * tz_check_geographic_tz() - verifies if the encoded timezone information contains geographic or offset info
4970  *
4971  * tzd(in) : timezone data
4972  * Returns: error if geographic timezone, NO_ERROR if offset timezone
4973  */
4974 int
4976 {
4977  TZ_DECODE_INFO tz_info;
4978 
4979  tz_decode_tz_id (tz_id, false, &tz_info);
4980 
4981  if (tz_info.type == TZ_REGION_ZONE)
4982  {
4984  return ER_TZ_GEOGRAPHIC_ZONE;
4985  }
4986  return NO_ERROR;
4987 }
4988 
4989 /*
4990  * tz_check_session_has_geographic_tz() - verifies if the session timezone contains geographic or offset info
4991  *
4992  * Returns: error if geographic timezone, NO_ERROR if offset timezone
4993  */
4994 int
4996 {
4997  TZ_REGION session_tz_region;
4998  tz_get_session_tz_region (&session_tz_region);
4999 
5000  if (session_tz_region.type != TZ_REGION_OFFSET)
5001  {
5003  return ER_TZ_GEOGRAPHIC_ZONE;
5004  }
5005  return NO_ERROR;
5006 }
5007 
5008 #if !defined(SERVER_MODE)
5009 /*
5010  * put_timezone_checksum - Saves the timezone checksum into DB
5011  * return: error code
5012  *
5013  * Note: This is called during database creation;
5014  *
5015  */
5016 int
5017 put_timezone_checksum (char *checksum)
5018 {
5019  DB_VALUE value;
5020  int au_save;
5021  int err_status = NO_ERROR;
5022 
5023  db_make_string (&value, checksum);
5024 
5025  AU_DISABLE (au_save);
5026  err_status = db_put_internal (Au_root, "timezone_checksum", &value);
5027  AU_ENABLE (au_save);
5028 
5029  return err_status;
5030 }
5031 #endif /* SERVER_MODE */
5032 
5033 /*
5034  * check_timezone_compat - checks compatibility between a client timezone checksum and a server timezone checksum
5035  *
5036  * Returns : error code
5037  * client_checksum(in): client checksum
5038  * server_checksum(in): server checksum
5039  * client_text(in): text to display in message error for client(this can be "server" when checking server vs database)
5040  * server_text(in): text to display in message error for server(this can be "database" when checking server vs database)
5041  */
5042 int
5043 check_timezone_compat (const char *client_checksum, const char *server_checksum, const char *client_text,
5044  const char *server_text)
5045 {
5046  assert (client_checksum != NULL);
5047  assert (server_checksum != NULL);
5048  assert (client_text != NULL);
5049  assert (server_text != NULL);
5050 
5051  if (strcmp (client_checksum, server_checksum) != 0)
5052  {
5055  }
5056 
5057  return NO_ERROR;
5058 }
5059 
5060 /*
5061  * tz_tzid_convert_region_to_offset - if the timezone encoded in tz_id is of region type the function converts
5062  * it to an offset type
5063  *
5064  * Returns :
5065  * tz_id(in): timezone id
5066  */
5067 void
5069 {
5070  unsigned int flag;
5071 
5072  flag = ((*tz_id) & TZ_MASK_TZ_ID_FLAG) >> TZ_BIT_SHIFT_TZ_ID_FLAG;
5073 
5074  if (flag == 0)
5075  {
5076  TZ_DECODE_INFO tz_info;
5077  int total_offset;
5078 
5079  tz_decode_tz_id (tz_id, true, &tz_info);
5080  assert (tz_info.zone.p_zone_off_rule != NULL);
5081  total_offset = tz_info.zone.p_zone_off_rule->gmt_off;
5082 
5083  if (tz_info.zone.p_zone_off_rule->ds_type == DS_TYPE_RULESET_ID && tz_info.zone.p_ds_rule != NULL)
5084  {
5085  total_offset += tz_info.zone.p_ds_rule->save_time;
5086  }
5087 
5088  tz_info.type = TZ_REGION_OFFSET;
5089  tz_info.offset = total_offset;
5090  tz_encode_tz_id (&tz_info, tz_id);
5091  }
5092 }
5093 
5094 /*
5095  * tz_create_datetimetz_from_utc () - Creates a datetimetz from an UTC time and a timezone region
5096  *
5097  * Return: error code
5098  * src_dt(in): datetime value in UTC reference
5099  * dest_region(in): timezone region for dest_dt_tz
5100  * dest_dt_tz(out): DATETIMETZ value
5101  *
5102  */
5103 int
5104 tz_create_datetimetz_from_utc (const DB_DATETIME * src_dt, const TZ_REGION * dest_region, DB_DATETIMETZ * dest_dt_tz)
5105 {
5106  int er_status = NO_ERROR;
5107  TZ_DECODE_INFO tz_info;
5108 
5109  tz_decode_tz_region (dest_region, &tz_info);
5110 
5111  er_status = tz_datetime_utc_conv (src_dt, &tz_info, true, true, &(dest_dt_tz->datetime));
5112  if (er_status != NO_ERROR)
5113  {
5114  return er_status;
5115  }
5116 
5117  tz_encode_tz_id (&tz_info, &(dest_dt_tz->tz_id));
5118 
5119  return er_status;
5120 }
5121 
5122 /*
5123  * tz_create_datetimetz_from_parts() - creates a datetimetz from month, day, year, hour, minutes, seconds and
5124  * milliseconds
5125  *
5126  * Returns error or no error
5127  * m(in): month
5128  * d(in): day
5129  * y(in): year
5130  * h(in): hour
5131  * mi(in): minute
5132  * s(in): second
5133  * ms(in): millisecond
5134  * tz_id(in): timezone id
5135  * dt_tz(out): result datetimetz
5136  */
5137 int
5138 tz_create_datetimetz_from_parts (const int m, const int d, const int y, const int h, const int mi, const int s,
5139  const int ms, const TZ_ID * tz_id, DB_DATETIMETZ * dt_tz)
5140 {
5141  DB_DATETIME utc_datetime;
5142  DB_DATETIMETZ dt_tz_utc;
5143  int error_status = NO_ERROR;
5144 
5145  error_status = db_datetime_encode (&utc_datetime, m, d, y, h, mi, s, ms);
5146  if (error_status != NO_ERROR)
5147  {
5148  return error_status;
5149  }
5150 
5151  dt_tz_utc.datetime = utc_datetime;
5152 
5153  if (tz_id != NULL)
5154  {
5155  dt_tz_utc.tz_id = *tz_id;
5156  error_status = tz_datetimetz_fix_zone (&dt_tz_utc, dt_tz);
5157  }
5158  else
5159  {
5160  TZ_REGION tz_session_region;
5161 
5162  tz_get_session_tz_region (&tz_session_region);
5163  error_status = tz_create_datetimetz_from_utc (&utc_datetime, &tz_session_region, dt_tz);
5164  }
5165 
5166  return error_status;
5167 }
5168 
5169 /*
5170  * set_new_zone_id() - Sets the new timezone id for the new timezone library using the old timezone library
5171  *
5172  * Returns error or no error
5173  * tz_info (in/out): pointer to tz_info
5174  *
5175  */
5176 static int
5178 {
5179  const char *timezone_name = NULL;
5180  unsigned int new_zone_id;
5181  int err_status = NO_ERROR;
5182 
5183  timezone_name = tz_Timezone_data.names[tz_info->zone.zone_id].name;
5185  new_zone_id = tz_get_zone_id_by_name (timezone_name, strlen (timezone_name));
5186  if (new_zone_id == (unsigned int) -1)
5187  {
5188  err_status = ER_TZ_INVALID_TIMEZONE;
5189  }
5190  else
5191  {
5192  tz_info->zone.zone_id = new_zone_id;
5193  }
5194 
5195  return err_status;
5196 }
5197 
5198 /*
5199  * conv_tz() - Converts a tz type from one time library to another
5200  *
5201  * Returns error or no error
5202  * p_out (out): pointer to output timezone data type
5203  * p_in (in): pointer to input timezone data type
5204  * type (in): timezone type
5205  *
5206  * NOTE: It does not make sense to use the function as NON-SA_MODE.
5207  */
5208 int
5209 conv_tz (void *p_out, const void *p_in, DB_TYPE type)
5210 {
5211  int err_status = NO_ERROR;
5212  TZ_DATA save_data;
5213 
5214  /* Save the state */
5215  save_data = tz_Timezone_data;
5216  switch (type)
5217  {
5218  case DB_TYPE_TIMESTAMPTZ:
5219  {
5220  DB_TIMESTAMPTZ *current, *to_be;
5221  DB_DATE date_local;
5222  DB_TIME time_local;
5223  TZ_DECODE_INFO tz_info;
5224  DB_DATETIME src_dt, dest_dt;
5225  DB_TIMESTAMP timestamp_utc;
5226 
5227  current = (DB_TIMESTAMPTZ *) p_in;
5228  to_be = (DB_TIMESTAMPTZ *) p_out;
5229 
5230  tz_decode_tz_id (&(current->tz_id), true, &tz_info);
5231  if (tz_info.type == TZ_REGION_OFFSET)
5232  {
5233  *to_be = *current;
5234  return NO_ERROR;
5235  }
5236 
5237 #if defined (SA_MODE)
5238  if (tz_Is_backward_compatible_timezone[tz_info.zone.zone_id] == true)
5239  {
5240  err_status = set_new_zone_id (&tz_info);
5241  if (err_status != NO_ERROR)
5242  {
5243  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
5244  goto exit;
5245  }
5246  tz_encode_tz_id (&tz_info, &(to_be->tz_id));
5247  to_be->timestamp = current->timestamp;
5248  goto exit;
5249  }
5250 #else /* !SA_MODE */
5251  /* NON SA_MODE have no interest. */
5252 #endif /* !SA_MODE */
5253 
5254  err_status = db_timestamp_decode_w_tz_id (&(current->timestamp), &(current->tz_id), &date_local, &time_local);
5255  if (err_status != NO_ERROR)
5256  {
5257  goto exit;
5258  }
5259 
5260  src_dt.date = date_local;
5261  src_dt.time = time_local * 1000;
5262 
5263  err_status = set_new_zone_id (&tz_info);
5264  if (err_status != NO_ERROR)
5265  {
5266  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
5267  goto exit;
5268  }
5269 
5270  err_status = tz_datetime_utc_conv (&src_dt, &tz_info, false, false, &dest_dt);
5271  /* If we get an error it means that the abbreviation does no longer exist
5272  * Then we must try to convert without the abbreviation
5273  */
5274  if (err_status != NO_ERROR)
5275  {
5276  tz_info.zone.dst_str[0] = '\0';
5277  err_status = tz_datetime_utc_conv (&src_dt, &tz_info, false, false, &dest_dt);
5278  if (err_status != NO_ERROR)
5279  {
5280  goto exit;
5281  }
5282  }
5283 
5284  dest_dt.time /= 1000;
5285  tz_encode_tz_id (&tz_info, &(to_be->tz_id));
5286  /* Encode UTC time for timestamptz */
5287  db_timestamp_encode_utc (&dest_dt.date, &dest_dt.time, &timestamp_utc);
5288  to_be->timestamp = timestamp_utc;
5289  }
5290  break;
5291 
5292  case DB_TYPE_DATETIMETZ:
5293  {
5294  DB_DATETIMETZ *current, *to_be;
5295  TZ_DECODE_INFO tz_info;
5296  DB_DATETIME dest_dt;
5297  DB_DATETIME datetime_local;
5298 
5299  current = (DB_DATETIMETZ *) p_in;
5300  to_be = (DB_DATETIMETZ *) p_out;
5301 
5302  tz_decode_tz_id (&(current->tz_id), true, &tz_info);
5303  if (tz_info.type == TZ_REGION_OFFSET)
5304  {
5305  *to_be = *current;
5306  return NO_ERROR;
5307  }
5308 
5309 #if defined (SA_MODE)
5310  if (tz_Is_backward_compatible_timezone[tz_info.zone.zone_id] == true)
5311  {
5312  err_status = set_new_zone_id (&tz_info);
5313  if (err_status != NO_ERROR)
5314  {
5315  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
5316  goto exit;
5317  }
5318  tz_encode_tz_id (&tz_info, &(to_be->tz_id));
5319  to_be->datetime = current->datetime;
5320  goto exit;
5321  }
5322 #else /* !SA_MODE */
5323  /* NON SA_MODE have no interest. */
5324 #endif /* !SA_MODE */
5325 
5326  err_status = tz_utc_datetimetz_to_local (&(current->datetime), &(current->tz_id), &datetime_local);
5327  if (err_status)
5328  {
5329  goto exit;
5330  }
5331 
5332  err_status = set_new_zone_id (&tz_info);
5333  if (err_status != NO_ERROR)
5334  {
5335  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
5336  goto exit;
5337  }
5338 
5339  err_status = tz_datetime_utc_conv (&datetime_local, &tz_info, false, false, &dest_dt);
5340  /* If we get an error it means that the abbreviation does no longer exist
5341  * then we must try to convert without the abbreviation
5342  */
5343  if (err_status != NO_ERROR)
5344  {
5345  tz_info.zone.dst_str[0] = '\0';
5346  err_status = tz_datetime_utc_conv (&datetime_local, &tz_info, false, false, &dest_dt);
5347  if (err_status != NO_ERROR)
5348  {
5349  goto exit;
5350  }
5351  }
5352 
5353  tz_encode_tz_id (&tz_info, &(to_be->tz_id));
5354  to_be->datetime = dest_dt;
5355  }
5356  break;
5357 
5358  case DB_TYPE_TIMESTAMPLTZ:
5359  {
5360  DB_TIMESTAMP *current, *to_be;
5361  TZ_ID ses_tz_id;
5362  DB_DATE date_local;
5363  DB_TIME time_local;
5364  DB_DATETIME src_dt, dest_dt;
5365  TZ_DECODE_INFO tz_info;
5366 
5367  current = (DB_TIMESTAMP *) p_in;
5368  to_be = (DB_TIMESTAMP *) p_out;
5369 
5370  err_status = tz_create_session_tzid_for_timestamp (current, &ses_tz_id);
5371  if (err_status != NO_ERROR)
5372  {
5373  goto exit;
5374  }
5375 
5376  tz_decode_tz_id (&ses_tz_id, true, &tz_info);
5377 
5378 #if defined (SA_MODE)
5379  if ((tz_info.type == TZ_REGION_OFFSET) || (tz_Is_backward_compatible_timezone[tz_info.zone.zone_id] == true))
5380  {
5381  *to_be = *current;
5382  return NO_ERROR;
5383  }
5384 #else /* !SA_MODE */
5385  /* NON SA_MODE have no interest. */
5386 #endif /* !SA_MODE */
5387 
5388  err_status = db_timestamp_decode_w_tz_id (current, &ses_tz_id, &date_local, &time_local);
5389  if (err_status != NO_ERROR)
5390  {
5391  goto exit;
5392  }
5393 
5394  src_dt.date = date_local;
5395  src_dt.time = time_local * 1000;
5396 
5397  err_status = set_new_zone_id (&tz_info);
5398  if (err_status != NO_ERROR)
5399  {
5400  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
5401  goto exit;
5402  }
5403 
5404  err_status = tz_datetime_utc_conv (&src_dt, &tz_info, false, false, &dest_dt);
5405  if (err_status != NO_ERROR)
5406  {
5407  goto exit;
5408  }
5409 
5410  dest_dt.time /= 1000;
5411  db_timestamp_encode_utc (&dest_dt.date, &dest_dt.time, to_be);
5412  }
5413  break;
5414 
5415  case DB_TYPE_DATETIMELTZ:
5416  {
5417  DB_DATETIME *current, *to_be;
5418  TZ_ID ses_tz_id;
5419  TZ_DECODE_INFO tz_info;
5420  DB_DATETIME datetime_local;
5421 
5422  current = (DB_DATETIME *) p_in;
5423  to_be = (DB_DATETIME *) p_out;
5424 
5425  err_status = tz_create_session_tzid_for_datetime (current, true, &ses_tz_id);
5426  if (err_status != NO_ERROR)
5427  {
5428  goto exit;
5429  }
5430 
5431  tz_decode_tz_id (&ses_tz_id, true, &tz_info);
5432 
5433 #if defined (SA_MODE)
5434  if ((tz_info.type == TZ_REGION_OFFSET) || (tz_Is_backward_compatible_timezone[tz_info.zone.zone_id] == true))
5435  {
5436  *to_be = *current;
5437  return NO_ERROR;
5438  }
5439 #else /* !SA_MODE */
5440  /* NON SA_MODE have no interest. */
5441 #endif /* !SA_MODE */
5442 
5443  err_status = tz_utc_datetimetz_to_local (current, &ses_tz_id, &datetime_local);
5444  if (err_status)
5445  {
5446  goto exit;
5447  }
5448 
5449  err_status = set_new_zone_id (&tz_info);
5450  if (err_status != NO_ERROR)
5451  {
5452  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, err_status, 0);
5453  goto exit;
5454  }
5455 
5456  err_status = tz_datetime_utc_conv (&datetime_local, &tz_info, false, false, to_be);
5457  if (err_status != NO_ERROR)
5458  {
5459  goto exit;
5460  }
5461  }
5462  break;
5463 
5464  default:
5465  assert (false);
5466  break;
5467  }
5468 
5469 exit:
5470  tz_set_data (&save_data);
5471 
5472  return err_status;
5473 }
5474 
5475 //TODO: make tz_get_offset_in_mins get into account DST
5476 /*
5477  * tz_get_offset_in_mins () - time zone offset in minutes from GMT
5478  */
5479 int
5481 {
5482  time_t currtime;
5483  struct tm *timeinfo;
5484 
5485  time (&currtime);
5486  timeinfo = gmtime (&currtime);
5487  time_t utc = mktime (timeinfo);
5488  timeinfo = localtime (&currtime);
5489  time_t local = mktime (timeinfo);
5490 
5491  // Get offset in minutes from UTC
5492  int offsetFromUTC = difftime (utc, local) / 60;
5493 
5494  return offsetFromUTC;
5495 }
int julian_encode(int m, int d, int y)
Definition: db_date.c:113
unsigned int TZ_ID
Definition: dbtype_def.h:756
int char_isspace(int c)
Definition: chartype.c:109
int tz_create_session_tzid_for_time(const DB_TIME *src_time, bool src_is_utc, TZ_ID *tz_id)
Definition: tz_support.c:1091
#define DATE_DIFF_MATCH_SAFE_THRESHOLD_DAYS
Definition: tz_support.h:82
void * handle
TZ_DS_RULESET * ds_rulesets
cubthread::entry * thread_get_thread_entry_info(void)
#define NO_ERROR
Definition: error_code.h:46
int check_timezone_compat(const char *client_checksum, const char *server_checksum, const char *client_text, const char *server_text)
Definition: tz_support.c:5043
#define AU_DISABLE(save)
Definition: authenticate.h:106
const char * name
#define TZ_MIN_OFFSET
Definition: tz_support.c:93
static int tz_print_tz_offset(char *result, int tz_offset)
Definition: tz_support.c:884
#define ZONE_MAX
Definition: tz_support.h:87
#define BO_IS_SERVER_RESTARTED()
Definition: boot_sr.h:84
int tz_timestamptz_fix_zone(const DB_TIMESTAMPTZ *src_ts_tz, DB_TIMESTAMPTZ *dest_ts_tz)
Definition: tz_support.c:1843
unsigned char until_hour
unsigned char month
DB_BIGINT tz_timestamp_encode_leap_sec_adj(const int year_century, const int year, const int mon, const int day)
Definition: tz_support.c:415
void showstmt_free_array_context(THREAD_ENTRY *thread_p, SHOWSTMT_ARRAY_CONTEXT *ctx)
Definition: show_scan.c:373
const char * var_format
#define ER_TZ_INTERNAL_ERROR
Definition: error_code.h:1488
#define TZ_DS_ID_MAX
Definition: tz_support.h:78
static int tz_Initialized
Definition: tz_support.c:101
MOP Au_root
Definition: authenticate.c:300
#define TZLIB_GET_ADDR(v, SYM_NAME, SYM_TYPE, lh)
Definition: tz_support.c:186
int db_add_int_to_datetime(DB_DATETIME *datetime, DB_BIGINT bi2, DB_DATETIME *result_datetime)
Definition: db_date.c:4656
DB_TIMESTAMP timestamp
Definition: dbtype_def.h:766
enum tz_region_type TZ_REGION_TYPE
Definition: dbtype_def.h:1233
#define ER_TZ_DURING_DS_LEAP
Definition: error_code.h:1493
DB_TYPE
Definition: dbtype_def.h:670
int tz_create_datetimetz_from_ses(const DB_DATETIME *dt, DB_DATETIMETZ *dt_tz)
Definition: tz_support.c:1493
void tz_timestamp_decode_no_leap_sec(int timestamp, int *yearp, int *monthsp, int *dayp, int *hoursp, int *minutesp, int *secondsp)
Definition: tz_support.c:601
#define ER_FAILED
Definition: error_code.h:47
TZ_REGION_TYPE type
Definition: tz_support.c:59
const TZ_DATA * tz_get_data(void)
Definition: tz_support.c:687
TZ_DS_CHANGE_ON change_on
#define FULL_DATE(jul_date, time_sec)
Definition: tz_support.c:86
#define ER_TZ_DURING_OFFSET_RULE_LEAP
Definition: error_code.h:1533
static void tz_encode_tz_id(const TZ_DECODE_INFO *tz_info, TZ_ID *tz_id)
Definition: tz_support.c:1891
static bool is_in_overlap_interval(const TZ_TIME_TYPE time_type, const full_date_t offset_rule_diff, const full_date_t gmt_diff, const int save_time_diff)
Definition: tz_support.c:2744
int tz_create_datetimetz_from_offset(const DB_DATETIME *dt, const int tzh, const int tzm, DB_DATETIMETZ *dt_tz)
Definition: tz_support.c:4068
int tz_create_datetimetz_from_zoneid_and_tzd(const DB_DATETIME *dt, TZ_REGION *default_tz_region, const int zone_id, const char *tzd, const int tzd_len, bool is_time_tz, DB_DATETIMETZ *dt_tz)
Definition: tz_support.c:4212
const char * letter_abbrev
const TZ_ID * tz_get_utc_tz_id(void)
Definition: tz_support.c:816
int tz_create_timestamptz_from_offset(const DB_DATE *date, const DB_TIME *time, const int tzh, const int tzm, DB_TIMESTAMPTZ *timestamp_tz)
Definition: tz_support.c:4107
#define ER_TZ_INCOMPATIBLE_TIMEZONE_LIBRARIES
Definition: error_code.h:1514
void tz_get_session_tz_region(TZ_REGION *tz_region)
Definition: tz_support.c:767
unsigned long int thread_id_t
int tz_resolve_os_timezone(char *timezone, int buf_len)
Definition: tz_support.c:4588
void tz_set_tz_region_system(const TZ_REGION *tz_region)
Definition: tz_support.c:4650
static int tz_zone_info_to_str(const TZ_DECODE_INFO *tz_info, char *tz_str, const int tz_str_size)
Definition: tz_support.c:1652
#define LEN_MIN_HOUR_SEC
int tz_load_with_library_path(TZ_DATA *tzd, const char *timezone_library_path)
Definition: tz_support.c:4937
char * envvar_libdir_file(char *path, size_t size, const char *filename)
cubthread::manager * thread_get_manager(void)
int tz_create_datetimetz_from_parts(const int m, const int d, const int y, const int h, const int mi, const int s, const int ms, const TZ_ID *tz_id, DB_DATETIMETZ *dt_tz)
Definition: tz_support.c:5138
int tz_create_timestamptz_from_zoneid_and_tzd(const DB_DATE *date, const DB_TIME *time, TZ_REGION *default_tz_region, const int zone_id, const char *tzd, const int tzd_len, DB_TIMESTAMPTZ *timestamp_tz)
Definition: tz_support.c:4280
int tz_check_geographic_tz(const TZ_ID *tz_id)
Definition: tz_support.c:4975
const char * std_format
int tz_load(void)
Definition: tz_support.c:337
static int starts_with(const char *prefix, const char *str)
Definition: tz_support.c:4349
unsigned char day
int tz_conv_tz_time_w_zone_name(const DB_TIME *time_source, const char *source_zone, int len_source, const char *dest_zone, int len_dest, DB_TIME *time_dest)
Definition: tz_support.c:1528
static TZ_DATA tz_New_timezone_data
Definition: tz_support.c:123
#define diff
Definition: mprec.h:352
int er_errid(void)
TZ_TIME_TYPE at_time_type
SHOWSTMT_ARRAY_CONTEXT * showstmt_alloc_array_context(THREAD_ENTRY *thread_p, int num_total, int num_cols)
Definition: show_scan.c:336
int tz_conv_tz_datetime_w_region(const DB_DATETIME *src_dt, const TZ_REGION *src_tz_region, const TZ_REGION *dest_tz_region, DB_DATETIME *dest_dt, TZ_ID *src_tz_id_out, TZ_ID *dest_tz_id_out)
Definition: tz_support.c:3812
unsigned int dst_id
Definition: tz_support.c:67
struct tz_decode_info::@31::@33 zone
#define TZ_BIT_SHIFT_TZ_ID_FLAG
Definition: tz_support.c:97
static DB_DATE tz_get_current_date(void)
Definition: tz_support.c:852
static int tz_conv_tz_datetime_w_zone_info(const DB_DATETIME *src_dt, const TZ_DECODE_INFO *src_zone_info_in, const TZ_DECODE_INFO *dest_zone_info_in, DB_DATETIME *dest_dt, TZ_DECODE_INFO *src_zone_info_out, TZ_DECODE_INFO *dest_zone_info_out)
Definition: tz_support.c:3730
static int tz_load_data_from_lib(TZ_DATA *tzd, void *lib_handle)
Definition: tz_support.c:281
TZ_TIME_TYPE until_time_type
#define TZLIB_GET_VAL(v, SYM_NAME, SYM_TYPE, lh)
Definition: tz_support.c:197
TZ_COUNTRY * countries
#define MILLIS_IN_A_DAY
Definition: tz_support.c:95
void THREAD_ENTRY
#define TZ_IS_ZONE_VALID_DECODE_INFO(tz_info)
Definition: tz_support.h:118
TZ_REGION * session_get_session_tz_region(THREAD_ENTRY *thread_p)
Definition: session.c:2950
int db_make_string(DB_VALUE *value, DB_CONST_C_CHAR str)
static const int tz_Days_of_month[]
Definition: tz_support.c:126
int tz_str_read_number(const char *str, const char *str_end, const bool strict, const bool read_sign, int *val, const char **str_next)
Definition: tz_support.c:2130
int tz_get_best_match_zone(const char *name, int *size)
Definition: tz_support.c:4157
#define ER_TZ_INVALID_DST
Definition: error_code.h:1490
int tz_create_datetimetz(const DB_DATETIME *dt, const char *tz_str, const int tz_size, const TZ_REGION *default_tz_region, DB_DATETIMETZ *dt_tz, const char **end_tz_str)
Definition: tz_support.c:1383
unsigned int DB_TIMESTAMP
Definition: dbtype_def.h:759
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
TZ_DS_RULE * p_ds_rule
Definition: tz_support.c:72
#define assert(x)
TZ_TIME_TYPE
char checksum[TZ_CHECKSUM_SIZE+1]
static int get_closest_ds_rule(const int src_julian_date, const int src_time_sec, const TZ_DS_RULESET *ds_ruleset, const TZ_DATA *tzd, const DS_SEARCH_DIRECTION direction)
Definition: tz_support.c:2648
int tz_create_session_tzid_for_datetime(const DB_DATETIME *src_dt, bool src_is_utc, TZ_ID *tz_id)
Definition: tz_support.c:1037
int tz_str_read_time(const char *str, const char *str_end, bool need_minutes, bool allow_sec60, int *hour, int *min, int *sec, const char **str_next)
Definition: tz_support.c:2186
DB_BIGINT full_date_t
Definition: tz_support.h:125
#define ER_TIME_CONVERSION
Definition: error_code.h:981
#define ABS(i)
Definition: tz_support.c:90
int db_timestamp_encode_utc(const DB_DATE *date, const DB_TIME *timeval, DB_TIMESTAMP *utime)
Definition: db_date.c:635
int tz_full_timezones_start_scan(THREAD_ENTRY *thread_p, int show_type, DB_VALUE **arg_values, int arg_cnt, void **ptr)
Definition: tz_support.c:4775
static TZ_DATA tz_Timezone_data
Definition: tz_support.c:120
#define MAX_LEN_OFFSET
Definition: tz_support.h:45
#define TZ_OFFSET_MASK
Definition: tz_support.c:98
char dst_str[TZ_DS_STRING_SIZE]
Definition: tz_support.c:68
const char * save_format
int tz_str_to_seconds(const char *str, const char *str_end, int *seconds, const char **str_next, const bool is_offset)
Definition: tz_support.c:2278
static int get_date_diff_from_ds_rule(const int src_julian_date, const int src_time_sec, const TZ_DS_RULE *ds_rule, const DS_SEARCH_DIRECTION direction, full_date_t *date_diff)
Definition: tz_support.c:2601
int tz_get_ds_change_julian_date_diff(const int src_julian_date, const TZ_DS_RULE *ds_rule, const int year, int *ds_rule_julian_date, full_date_t *date_diff)
Definition: tz_support.c:2333
DB_DATETIME datetime
Definition: dbtype_def.h:783
int tz_id_to_str(const TZ_ID *tz_id, char *tz_str, const int tz_str_size)
Definition: tz_support.c:1789
TZ_TIMEZONE * p_timezone
Definition: tz_support.c:70
static void tz_timestamp_decode_leap_sec_adj(int timestamp, int *yearp, int *monthsp, int *dayp, int *hoursp, int *minutesp, int *secondsp)
Definition: tz_support.c:474
#define min(a, b)
int tz_str_to_region(const char *tz_str, const int tz_str_size, TZ_REGION *tz_region)
Definition: tz_support.c:1286
void tz_tzid_convert_region_to_offset(TZ_ID *tz_id)
Definition: tz_support.c:5068
int tz_create_datetimetz_from_utc(const DB_DATETIME *src_dt, const TZ_REGION *dest_region, DB_DATETIMETZ *dest_dt_tz)
Definition: tz_support.c:5104
unsigned int zone_id
Definition: tz_support.c:65
TZ_NAME * names
#define SECONDS_IN_A_DAY
Definition: tz_support.c:99
#define LIB_TZ_NAME
Definition: tz_support.h:59
unsigned char until_min
static TZ_REGION tz_Region_system
Definition: tz_support.c:102
#define TZ_DS_STRING_SIZE
Definition: tz_support.h:85
int char_isdigit(int c)
Definition: chartype.c:73
static int tz_get_zone_id_by_name(const char *name, const int name_size)
Definition: tz_support.c:1109
#define NULL
Definition: freelistheap.h:34
#define ER_TZ_INVALID_TIMEZONE
Definition: error_code.h:1489
#define DAYS_IN_MONTH(m)
Definition: tz_support.h:65
int db_get_day_of_week(int year, int month, int day)
Definition: db_date.c:4723
#define IS_EMPTY_STR(s)
Definition: tz_support.h:67
int tz_datetimeltz_to_local(const DB_DATETIME *dt_ltz, DB_DATETIME *dt_local)
Definition: tz_support.c:1628
void tz_get_system_tz_region(TZ_REGION *tz_region)
Definition: tz_support.c:758
#define strlen(s1)
Definition: tz_support.c:53
unsigned int offset_id
Definition: tz_support.c:66
TZ_UNTIL_FLAG until_flag
TZ_REGION_TYPE type
Definition: dbtype_def.h:1238
void tz_timestamp_decode_sec(int timestamp, int *yearp, int *monthsp, int *dayp, int *hoursp, int *minutesp, int *secondsp)
Definition: tz_support.c:458
int db_timestamp_decode_w_tz_id(const DB_TIMESTAMP *utime, const TZ_ID *tz_id, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:902
#define TZ_INVALID_OFFSET
Definition: tz_support.c:92
static int get_saving_time_from_offset_rule(const TZ_OFFSET_RULE *offset_rule, const TZ_DATA *tzd, int *save_time)
Definition: tz_support.c:2692
DB_VALUE * showstmt_alloc_tuple_in_context(THREAD_ENTRY *thread_p, SHOWSTMT_ARRAY_CONTEXT *ctx)
Definition: show_scan.c:402
int conv_tz(void *p_out, const void *p_in, DB_TYPE type)
Definition: tz_support.c:5209
TZ_TIMEZONE * timezones
int db_put_internal(DB_OBJECT *obj, const char *name, DB_VALUE *value)
Definition: db_obj.c:347
unsigned char day_of_month
void tz_set_new_timezone_data(const TZ_DATA *data)
Definition: tz_support.c:729
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
ds_search_direction
Definition: tz_support.c:78
static int tz_fast_find_ds_rule(const TZ_DATA *tzd, const TZ_DS_RULESET *ds_ruleset, const int src_julian_date, const int src_year, const int src_month, int *ds_rule_id)
Definition: tz_support.c:2388
int64_t DB_BIGINT
Definition: dbtype_def.h:751
#define ER_DATE_CONVERSION
Definition: error_code.h:242
#define IS_LEAP_YEAR(y)
Definition: tz_support.h:62
#define CAST_BUFLEN
Definition: porting.h:471
#define TZ_MASK_TZ_ID_FLAG
Definition: tz_support.c:96
static void error(const char *msg)
Definition: gencat.c:331
int tz_timezones_start_scan(THREAD_ENTRY *thread_p, int show_type, DB_VALUE **arg_values, int arg_cnt, void **ptr)
Definition: tz_support.c:4716
unsigned char day_of_week
#define ER_TZ_GEOGRAPHIC_ZONE
Definition: error_code.h:1510
void tz_id_to_region(const TZ_ID *tz_id, TZ_REGION *tz_region)
Definition: tz_support.c:803
int tz_utc_datetimetz_to_local(const DB_DATETIME *dt_utc, const TZ_ID *tz_id, DB_DATETIME *dt_local)
Definition: tz_support.c:1571
#define TZ_OFFSET_ID_MAX
Definition: tz_support.h:77
#define ARG_FILE_LINE
Definition: error_manager.h:44
static void * tz_Lib_handle
Definition: tz_support.c:110
#define snprintf_dots_truncate(dest, max_len,...)
Definition: porting.h:323
int tz_get_first_weekday_around_date(const int year, const int month, const int weekday, const int ref_day, const bool before)
Definition: tz_support.c:2085
int tz_conv_tz_datetime_w_zone_name(const DB_DATETIME *src_dt, const char *source_zone, int len_source, const char *dest_zone, int len_dest, DB_DATETIME *dest_dt)
Definition: tz_support.c:3858
#define APPLY_NEXT_OFF_RULE()
Definition: tz_support.c:204
unsigned int DB_TIME
Definition: dbtype_def.h:754
#define AU_ENABLE(save)
Definition: authenticate.h:113
static void tz_decode_tz_id(const TZ_ID *tz_id, const bool is_full_decode, TZ_DECODE_INFO *tz_info)
Definition: tz_support.c:1957
static bool tz_check_ds_match_string(const TZ_OFFSET_RULE *off_rule, const TZ_DS_RULE *ds_rule, const char *ds_string, const char *default_abrev)
Definition: tz_support.c:2499
unsigned int DB_DATE
Definition: dbtype_def.h:771
void julian_decode(int jul, int *monthp, int *dayp, int *yearp, int *weekp)
Definition: db_date.c:196
enum ds_search_direction DS_SEARCH_DIRECTION
Definition: tz_support.c:83
const TZ_DATA * tz_get_new_timezone_data(void)
Definition: tz_support.c:713
int db_datetime_encode(DB_DATETIME *datetime, int month, int day, int year, int hour, int minute, int second, int millisecond)
Definition: db_date.c:4597
static int tz_datetime_utc_conv(const DB_DATETIME *src_dt, TZ_DECODE_INFO *tz_info, bool src_is_utc, bool only_tz_adjust, DB_DATETIME *dest_dt)
Definition: tz_support.c:2815
char * prm_get_string_value(PARAM_ID prm_id)
const char * tz_get_system_timezone(void)
Definition: tz_support.c:749
int tz_check_session_has_geographic_tz(void)
Definition: tz_support.c:4995
const char * default_abrev
int db_make_string_copy(DB_VALUE *value, DB_CONST_C_CHAR str)
unsigned int date
Definition: dbtype_def.h:776
int tz_get_offset_in_mins()
Definition: tz_support.c:5480
bool prm_get_bool_value(PARAM_ID prm_id)
int tz_create_timestamptz(const DB_DATE *date, const DB_TIME *time, const char *tz_str, const int tz_size, const TZ_REGION *default_tz_region, DB_TIMESTAMPTZ *ts_tz, const char **end_tz_str)
Definition: tz_support.c:1435
TZ_REGION * tz_get_client_tz_region_session(void)
Definition: tz_support.c:4662
entry * find_by_tid(thread_id_t tid)
const char * tz_get_session_local_timezone(void)
Definition: tz_support.c:739
void db_timestamp_decode_utc(const DB_TIMESTAMP *utime, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:781
static int get_year_to_apply_rule(const int src_year, const TZ_DS_RULE *ds_rule)
Definition: tz_support.c:2777
TZ_DS_RULE * ds_rules
char ** timezone_names
static bool tz_get_leapsec_support(void)
Definition: tz_support.c:402
int i
Definition: dynamic_load.c:954
int db_make_null(DB_VALUE *value)
#define TZ_MAX_FORMAT_SIZE
#define ER_TZ_INVALID_COMBINATION
Definition: error_code.h:1492
static const int tz_Days_up_to_month[]
Definition: tz_support.c:127
static int tz_load_library(const char *lib_file, void **handle)
Definition: tz_support.c:220
TZ_OFFSET_RULE * p_zone_off_rule
Definition: tz_support.c:71
unsigned short year
unsigned char in_month
const TZ_REGION * tz_get_utc_tz_region(void)
Definition: tz_support.c:828
unsigned char until_sec
int put_timezone_checksum(char *checksum)
Definition: tz_support.c:5017
int tz_get_timezone_offset(const char *tz_str, int tz_size, char *result, DB_DATETIME *utc_datetime)
Definition: tz_support.c:935
static int tz_offset(const bool src_is_utc, const TZ_TIME_TYPE until_time_type, const int gmt_offset_sec, const int ds_save_time)
Definition: tz_support.c:2559
#define TZ_MAX_JULIAN_DATE
Definition: tz_support.h:74
int tz_explain_tz_id(const TZ_ID *tz_id, char *tzr, const int tzr_size, char *tzdst, const int tzdst_size, int *tzh, int *tzm)
Definition: tz_support.c:3893
DB_TIMESTAMP DB_UTIME
Definition: dbtype_def.h:761
static int set_new_zone_id(TZ_DECODE_INFO *tz_info)
Definition: tz_support.c:5177
#define TZLIB_SYMBOL_NAME_SIZE
Definition: tz_support.h:44
TZ_LEAP_SEC * ds_leap_sec
void db_time_decode(DB_TIME *timeval, int *hourp, int *minutep, int *secondp)
Definition: db_date.c:432
#define LEN_MIN_HOUR
int tz_create_session_tzid_for_timestamp(const DB_UTIME *src_ts, TZ_ID *tz_id)
Definition: tz_support.c:1068
static void tz_encode_tz_region(const TZ_DECODE_INFO *tz_info, TZ_REGION *tz_region)
Definition: tz_support.c:1932
#define ER_TZ_LOAD_ERROR
Definition: error_code.h:1487
#define TZ_MAX_OFFSET
Definition: tz_support.c:94
static int tz_str_timezone_decode(const char *tz_str, const int tz_str_size, TZ_DECODE_INFO *tz_info, const char **tz_end)
Definition: tz_support.c:1170
#define TIME_OFFSET(is_utc, offset)
Definition: tz_support.c:88
static TZ_REGION tz_Region_session
Definition: tz_support.c:104
TZ_OFFSET_RULE * offset_rules
void tz_unload(void)
Definition: tz_support.c:381
static void tz_decode_tz_region(const TZ_REGION *tz_region, TZ_DECODE_INFO *tz_info)
Definition: tz_support.c:2053
const char ** p
Definition: dynamic_load.c:945
unsigned int zone_id
Definition: dbtype_def.h:1242
unsigned int time
Definition: dbtype_def.h:777
#define TZ_ZONE_ID_MAX
Definition: tz_support.h:76
void tz_set_data(const TZ_DATA *data)
Definition: tz_support.c:702
static const TZ_REGION * tz_get_invalid_tz_region(void)
Definition: tz_support.c:840
int tz_datetimetz_fix_zone(const DB_DATETIMETZ *src_dt_tz, DB_DATETIMETZ *dest_dt_tz)
Definition: tz_support.c:1815
#define DATE_DIFF_MATCH_SAFE_THRESHOLD_SEC
Definition: tz_support.h:83