File: my_tzinfo-t.c

package info (click to toggle)
mariadb 1%3A11.8.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 772,520 kB
  • sloc: ansic: 2,414,714; cpp: 1,791,394; asm: 381,336; perl: 62,905; sh: 49,647; pascal: 40,897; java: 39,363; python: 20,791; yacc: 20,432; sql: 17,907; xml: 12,344; ruby: 8,544; cs: 6,542; makefile: 6,145; ada: 1,879; lex: 1,193; javascript: 996; objc: 80; tcl: 73; awk: 46; php: 22
file content (197 lines) | stat: -rw-r--r-- 6,352 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
   Copyright (c) 2023, MariaDB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
 */

/*
  This file tests my_tzset/my_get_tzinfo APIs
*/
#include <my_global.h>
#include <my_sys.h>
#include "tap.h"
#include <stdlib.h>

/**
  Seconds since epoch used for "summer" timestamp
  Corresponds to Jul 22 2023 04:26:40 GMT
  Used to test timezone daylight savings UTC offset and DST abbreviation
*/
#define SUMMER_TIMESTAMP   1690000000

/**
  Seconds since epoch used for "winter" timestamp
  Corresponds to Nov 14 2023 22:13:20 GMT+
  Used to test standard (no daylight savings) UTC offset and abbreviation
*/
#define WINTER_TIMESTAMP   1700000000

#ifdef _WIN32
#define timegm _mkgmtime
#endif
/**
  Check expected offset from UTC, corresponding to specific
  timestamp.

  On Windows, it is possible that my_get_tzinfo() is using
  ICU to calculate offset.This function rechecks that value is the
  same when using C runtime's _mkgmtime().

  Elsewhere, my_get_tzinfo is taking this value from non-standard glibc
  extension struct tm::tm_gmtoff. This function rechecks that the value
  is the same if calculated with timegm().
*/
static void check_utc_offset(time_t t, long expected, const char *comment)
{
#if defined _WIN32 || defined __linux__
  struct tm local_time;
  long offset;
  localtime_r(&t, &local_time);
  offset= (long) (timegm(&local_time) - t);
  ok(offset == expected, "%s: Offset for timestamp %lld is %ld/%ld", comment,
      (long long) t,expected, offset);
#else
  skip(1, "no utc offset check");
#endif
}

/**
  Test my_tzset/my_get_tzinfo functions for a single named timezone.

  @param[in] tz_env. Timezone name, as used for TZ env.variable

  @param[in] expected_tznames. Expected "sytem_timezone" names.
             For example, expected names for timezone PST8PDT can
             be PST8PDT, PST or PDT

  @param[in] summer_gmt_off. Expected UTC offset, for SUMMER_TIMESTAMP
             For timezones with DST savings on northern hemisphere
             it is the expected DST offset from UTC

  @param[in] summer_time_abbr . Expected standard abbreviation
             corresponding to SUMMER_TIMESTAMP. For example, it is
             "PDT" for timezone PST8PDT

  @param[in] winter_gmt_off. Expected UTC offset, for WINTER_TIMESTAMP

  @param[in] winter_time_abbr . Expected standard abbreviation
             corresponding to WINTER_TIMESTAMP. For example, it is
             "PST" for timezone PST8PDT.
*/
void test_timezone(const char *tz_env, const char **expected_tznames,
                   long summer_gmt_off, const char *summer_time_abbr,
                   long winter_gmt_off, const char *winter_time_abbr)
{
  char timezone_name[64];
  int found;
  struct my_tz tz;

  setenv("TZ", tz_env, 1);
  my_tzset();
  my_tzname(timezone_name, sizeof(timezone_name));

  /* Check expected timezone names. */
  found= 0;
  for (int i= 0; expected_tznames[i]; i++)
  {
    if (!strcmp(expected_tznames[i], timezone_name))
    {
      found= 1;
      break;
    }
  }
  ok(found, "%s: timezone_name = %s", tz_env, timezone_name);
  my_tzinfo(SUMMER_TIMESTAMP, &tz);
  ok(summer_gmt_off == tz.seconds_offset, "%s: Summer GMT offset %ld", tz_env, tz.seconds_offset);
  check_utc_offset(SUMMER_TIMESTAMP,tz.seconds_offset, tz_env);

  ok(!strcmp(summer_time_abbr, tz.abbreviation), "%s: Summer time abbreviation %s",
     tz_env, tz.abbreviation);
  my_tzinfo(WINTER_TIMESTAMP, &tz);
  ok(winter_gmt_off == tz.seconds_offset, "%s: Winter GMT offset  %ld", tz_env, tz.seconds_offset);
  check_utc_offset(WINTER_TIMESTAMP, tz.seconds_offset, tz_env);
  ok(!strcmp(winter_time_abbr, tz.abbreviation), "%s: Winter time abbreviation %s",
     tz_env, tz.abbreviation);
}

/* Check default timezone.*/
static void test_default_timezone()
{
  char timezone_name[64];

  time_t timestamps[]= {SUMMER_TIMESTAMP, WINTER_TIMESTAMP, time(NULL)};
  size_t i;
  struct my_tz tz;
#ifdef _WIN32
  (void) putenv("TZ=");
#else
  unsetenv("TZ");
#endif

  my_tzset();
  my_tzname(timezone_name, sizeof(timezone_name));
#ifdef _WIN32
  /* Expect timezone name like Europe/Berlin */
  ok(strstr(timezone_name, "/") != NULL, "Default timezone name %s",
     timezone_name);
#else
  skip(1, "no test for default timezone name %s", timezone_name);
#endif

  for (i = 0; i < array_elements(timestamps); i++)
  {
    my_tzinfo(timestamps[i], &tz);
    ok(tz.seconds_offset % 60 == 0,
       "GMT offset is whole number of minutes %ld", tz.seconds_offset);
    check_utc_offset(timestamps[i], tz.seconds_offset, timezone_name);
    ok(strlen(tz.abbreviation) < 8, "tz abbreviation %s", tz.abbreviation);
  }
}

int main(int argc __attribute__((unused)), char *argv[])
{
  const char *PST8PDT_names[]= {"PST", "PDT", "PST8PDT", NULL};
  const char *GMT_names[]= {"GMT", "Etc/UTC", NULL};
  const char *GST_minus1GDT_names[]= {"GST", "GDT", NULL};
  const char *IST_names[]= {"IST",NULL};
  MY_INIT(argv[0]);

  plan(38);
  test_default_timezone();

  /*
    Test PST8PDT timezone
    Standard timezone, supported everywhere. Note - this one is supported by
    ICU, so it would be using ICU for calculation on Windows
  */
  test_timezone("PST8PDT", PST8PDT_names, -25200, "PDT", -28800, "PST");

  /*
    Test GMT. Supported by ICU, would be using ICU for calculations
  */
  test_timezone("GMT", GMT_names, 0, "GMT", 0, "GMT");

  /*
    Non-standard "Germany" timezone, taken from Windows tzset() documentation
    example. Unsupported by ICU, will be using C runtime on Windows for
    abbreviations, and offset calculations.
  */
  test_timezone("GST-1GDT", GST_minus1GDT_names, 7200, "GDT", 3600, "GST");

  /* India */
  test_timezone("IST-5:30", IST_names, 19800, "IST", 19800, "IST");

  my_end(0);
  return exit_status();
}