Age Owner Branch data TLA Line data Source code
1 : : /* Convert timestamp from pg_time_t to struct pg_tm. */
2 : :
3 : : /*
4 : : * This file is in the public domain, so clarified as of
5 : : * 1996-06-05 by Arthur David Olson.
6 : : *
7 : : * IDENTIFICATION
8 : : * src/timezone/localtime.c
9 : : */
10 : :
11 : : /*
12 : : * Leap second handling from Bradley White.
13 : : * POSIX-style TZ environment variable handling from Guy Harris.
14 : : */
15 : :
16 : : /* this file needs to build in both frontend and backend contexts */
17 : : #include "c.h"
18 : :
19 : : #include <fcntl.h>
20 : :
21 : : #include "datatype/timestamp.h"
22 : : #include "pgtz.h"
23 : :
24 : : #include "private.h"
25 : : #include "tzfile.h"
26 : :
27 : :
28 : : #ifndef WILDABBR
29 : : /*
30 : : * Someone might make incorrect use of a time zone abbreviation:
31 : : * 1. They might reference tzname[0] before calling tzset (explicitly
32 : : * or implicitly).
33 : : * 2. They might reference tzname[1] before calling tzset (explicitly
34 : : * or implicitly).
35 : : * 3. They might reference tzname[1] after setting to a time zone
36 : : * in which Daylight Saving Time is never observed.
37 : : * 4. They might reference tzname[0] after setting to a time zone
38 : : * in which Standard Time is never observed.
39 : : * 5. They might reference tm.tm_zone after calling offtime.
40 : : * What's best to do in the above cases is open to debate;
41 : : * for now, we just set things up so that in any of the five cases
42 : : * WILDABBR is used. Another possibility: initialize tzname[0] to the
43 : : * string "tzname[0] used before set", and similarly for the other cases.
44 : : * And another: initialize tzname[0] to "ERA", with an explanation in the
45 : : * manual page of what this "time zone abbreviation" means (doing this so
46 : : * that tzname[0] has the "normal" length of three characters).
47 : : */
48 : : #define WILDABBR " "
49 : : #endif /* !defined WILDABBR */
50 : :
51 : : static const char wildabbr[] = WILDABBR;
52 : :
53 : : static const char gmt[] = "GMT";
54 : :
55 : : /*
56 : : * The DST rules to use if a POSIX TZ string has no rules.
57 : : * Default to US rules as of 2017-05-07.
58 : : * POSIX does not specify the default DST rules;
59 : : * for historical reasons, US rules are a common default.
60 : : */
61 : : #define TZDEFRULESTRING ",M3.2.0,M11.1.0"
62 : :
63 : : /* structs ttinfo, lsinfo, state have been moved to pgtz.h */
64 : :
65 : : enum r_type
66 : : {
67 : : JULIAN_DAY, /* Jn = Julian day */
68 : : DAY_OF_YEAR, /* n = day of year */
69 : : MONTH_NTH_DAY_OF_WEEK, /* Mm.n.d = month, week, day of week */
70 : : };
71 : :
72 : : struct rule
73 : : {
74 : : enum r_type r_type; /* type of rule */
75 : : int r_day; /* day number of rule */
76 : : int r_week; /* week number of rule */
77 : : int r_mon; /* month number of rule */
78 : : int32 r_time; /* transition time of rule */
79 : : };
80 : :
81 : : /*
82 : : * Prototypes for static functions.
83 : : */
84 : :
85 : : static struct pg_tm *gmtsub(pg_time_t const *timep, int32 offset,
86 : : struct pg_tm *tmp);
87 : : static bool increment_overflow(int *ip, int j);
88 : : static bool increment_overflow_time(pg_time_t *tp, int32 j);
89 : : static int64 leapcorr(struct state const *sp, pg_time_t t);
90 : : static struct pg_tm *timesub(pg_time_t const *timep,
91 : : int32 offset, struct state const *sp,
92 : : struct pg_tm *tmp);
93 : : static bool typesequiv(struct state const *sp, int a, int b);
94 : :
95 : :
96 : : /*
97 : : * Section 4.12.3 of X3.159-1989 requires that
98 : : * Except for the strftime function, these functions [asctime,
99 : : * ctime, gmtime, localtime] return values in one of two static
100 : : * objects: a broken-down time structure and an array of char.
101 : : * Thanks to Paul Eggert for noting this.
102 : : */
103 : :
104 : : static struct pg_tm tm;
105 : :
106 : : /* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */
107 : : static void
1733 tgl@sss.pgh.pa.us 108 :CBC 16234 : init_ttinfo(struct ttinfo *s, int32 utoff, bool isdst, int desigidx)
109 : : {
110 : 16234 : s->tt_utoff = utoff;
2939 111 : 16234 : s->tt_isdst = isdst;
1733 112 : 16234 : s->tt_desigidx = desigidx;
2939 113 : 16234 : s->tt_ttisstd = false;
1733 114 : 16234 : s->tt_ttisut = false;
2939 115 : 16234 : }
116 : :
117 : : static int32
2004 118 : 161016 : detzcode(const char *const codep)
119 : : {
120 : : int32 result;
121 : : int i;
2939 122 : 161016 : int32 one = 1;
123 : 161016 : int32 halfmaxval = one << (32 - 2);
124 : 161016 : int32 maxval = halfmaxval - 1 + halfmaxval;
125 : 161016 : int32 minval = -1 - maxval;
126 : :
127 : 161016 : result = codep[0] & 0x7f;
128 [ + + ]: 644064 : for (i = 1; i < 4; ++i)
7289 bruce@momjian.us 129 : 483048 : result = (result << 8) | (codep[i] & 0xff);
130 : :
2939 tgl@sss.pgh.pa.us 131 [ + + ]: 161016 : if (codep[0] & 0x80)
132 : : {
133 : : /*
134 : : * Do two's-complement negation even on non-two's-complement machines.
135 : : * If the result would be minval - 1, return minval.
136 : : */
1429 137 : 27384 : result -= !TWOS_COMPLEMENT(int32) && result != 0;
2939 138 : 27384 : result += minval;
139 : : }
7289 bruce@momjian.us 140 : 161016 : return result;
141 : : }
142 : :
143 : : static int64
2004 tgl@sss.pgh.pa.us 144 : 628810 : detzcode64(const char *const codep)
145 : : {
146 : : uint64 result;
147 : : int i;
2939 148 : 628810 : int64 one = 1;
149 : 628810 : int64 halfmaxval = one << (64 - 2);
150 : 628810 : int64 maxval = halfmaxval - 1 + halfmaxval;
1429 151 : 628810 : int64 minval = -TWOS_COMPLEMENT(int64) - maxval;
152 : :
2939 153 : 628810 : result = codep[0] & 0x7f;
154 [ + + ]: 5030480 : for (i = 1; i < 8; ++i)
155 : 4401670 : result = (result << 8) | (codep[i] & 0xff);
156 : :
157 [ + + ]: 628810 : if (codep[0] & 0x80)
158 : : {
159 : : /*
160 : : * Do two's-complement negation even on non-two's-complement machines.
161 : : * If the result would be minval - 1, return minval.
162 : : */
1429 163 : 166512 : result -= !TWOS_COMPLEMENT(int64) && result != 0;
2939 164 : 166512 : result += minval;
165 : : }
5902 166 : 628810 : return result;
167 : : }
168 : :
169 : : static bool
2939 170 : 6329997 : differ_by_repeat(const pg_time_t t1, const pg_time_t t0)
171 : : {
172 : : if (TYPE_BIT(pg_time_t) - TYPE_SIGNED(pg_time_t) < SECSPERREPEAT_BITS)
173 : : return 0;
5902 174 : 6329997 : return t1 - t0 == SECSPERREPEAT;
175 : : }
176 : :
177 : : /* Input buffer for data read from a compiled tz file. */
178 : : union input_buffer
179 : : {
180 : : /* The first part of the buffer, interpreted as a header. */
181 : : struct tzhead tzhead;
182 : :
183 : : /* The entire buffer. */
184 : : char buf[2 * sizeof(struct tzhead) + 2 * sizeof(struct state)
185 : : + 4 * TZ_MAX_TIMES];
186 : : };
187 : :
188 : : /* Local storage needed for 'tzloadbody'. */
189 : : union local_storage
190 : : {
191 : : /* The results of analyzing the file's contents after it is opened. */
192 : : struct file_analysis
193 : : {
194 : : /* The input buffer. */
195 : : union input_buffer u;
196 : :
197 : : /* A temporary state used for parsing a TZ string in the file. */
198 : : struct state st;
199 : : } u;
200 : :
201 : : /* We don't need the "fullname" member */
202 : : };
203 : :
204 : : /* Load tz data from the file named NAME into *SP. Read extended
205 : : * format if DOEXTEND. Use *LSP for temporary storage. Return 0 on
206 : : * success, an errno value on failure.
207 : : * PG: If "canonname" is not NULL, then on success the canonical spelling of
208 : : * given name is stored there (the buffer must be > TZ_STRLEN_MAX bytes!).
209 : : */
210 : : static int
2489 211 : 9630 : tzloadbody(char const *name, char *canonname, struct state *sp, bool doextend,
212 : : union local_storage *lsp)
213 : : {
214 : : int i;
215 : : int fid;
216 : : int stored;
217 : : ssize_t nread;
2939 218 : 9630 : union input_buffer *up = &lsp->u.u;
219 : 9630 : int tzheadsize = sizeof(struct tzhead);
220 : :
221 : 9630 : sp->goback = sp->goahead = false;
222 : :
223 [ - + ]: 9630 : if (!name)
224 : : {
2939 tgl@sss.pgh.pa.us 225 :UBC 0 : name = TZDEFAULT;
226 [ # # ]: 0 : if (!name)
227 : 0 : return EINVAL;
228 : : }
229 : :
6390 tgl@sss.pgh.pa.us 230 [ - + ]:CBC 9630 : if (name[0] == ':')
6390 tgl@sss.pgh.pa.us 231 :UBC 0 : ++name;
232 : :
6390 tgl@sss.pgh.pa.us 233 :CBC 9630 : fid = pg_open_tzfile(name, canonname);
234 [ + + ]: 9630 : if (fid < 0)
2939 235 : 294 : return ENOENT; /* pg_open_tzfile may not set errno */
236 : :
237 : 9336 : nread = read(fid, up->buf, sizeof up->buf);
238 [ - + ]: 9336 : if (nread < tzheadsize)
239 : : {
2939 tgl@sss.pgh.pa.us 240 [ # # ]:UBC 0 : int err = nread < 0 ? errno : EINVAL;
241 : :
242 : 0 : close(fid);
243 : 0 : return err;
244 : : }
2939 tgl@sss.pgh.pa.us 245 [ - + ]:CBC 9336 : if (close(fid) < 0)
2939 tgl@sss.pgh.pa.us 246 :UBC 0 : return errno;
5902 tgl@sss.pgh.pa.us 247 [ + + ]:CBC 28008 : for (stored = 4; stored <= 8; stored *= 2)
248 : : {
2939 249 : 18672 : int32 ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
1733 250 : 18672 : int32 ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
2396 251 : 18672 : int64 prevtr = 0;
252 : 18672 : int32 prevcorr = 0;
2939 253 : 18672 : int32 leapcnt = detzcode(up->tzhead.tzh_leapcnt);
254 : 18672 : int32 timecnt = detzcode(up->tzhead.tzh_timecnt);
255 : 18672 : int32 typecnt = detzcode(up->tzhead.tzh_typecnt);
256 : 18672 : int32 charcnt = detzcode(up->tzhead.tzh_charcnt);
257 : 18672 : char const *p = up->buf + tzheadsize;
258 : :
259 : : /*
260 : : * Although tzfile(5) currently requires typecnt to be nonzero,
261 : : * support future formats that may allow zero typecnt in files that
262 : : * have a TZ string and no transitions.
263 : : */
264 [ + - + - : 37344 : if (!(0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
+ - ]
2004 265 [ + - + - ]: 18672 : && 0 <= typecnt && typecnt < TZ_MAX_TYPES
2939 266 [ + - + - ]: 18672 : && 0 <= timecnt && timecnt < TZ_MAX_TIMES
267 [ + - + - ]: 18672 : && 0 <= charcnt && charcnt < TZ_MAX_CHARS
268 [ + - + - ]: 18672 : && (ttisstdcnt == typecnt || ttisstdcnt == 0)
1733 269 [ - + ]: 18672 : && (ttisutcnt == typecnt || ttisutcnt == 0)))
2939 tgl@sss.pgh.pa.us 270 :UBC 0 : return EINVAL;
2939 tgl@sss.pgh.pa.us 271 :CBC 18672 : if (nread
272 : : < (tzheadsize /* struct tzhead */
2489 273 : 18672 : + timecnt * stored /* ats */
2939 274 : 18672 : + timecnt /* types */
275 : 18672 : + typecnt * 6 /* ttinfos */
276 : 18672 : + charcnt /* chars */
277 : 18672 : + leapcnt * (stored + 4) /* lsinfos */
278 : 18672 : + ttisstdcnt /* ttisstds */
1733 279 [ - + ]: 18672 : + ttisutcnt)) /* ttisuts */
2939 tgl@sss.pgh.pa.us 280 :UBC 0 : return EINVAL;
2939 tgl@sss.pgh.pa.us 281 :CBC 18672 : sp->leapcnt = leapcnt;
282 : 18672 : sp->timecnt = timecnt;
283 : 18672 : sp->typecnt = typecnt;
284 : 18672 : sp->charcnt = charcnt;
285 : :
286 : : /*
287 : : * Read transitions, discarding those out of pg_time_t range. But
288 : : * pretend the last transition before TIME_T_MIN occurred at
289 : : * TIME_T_MIN.
290 : : */
291 : 18672 : timecnt = 0;
7268 bruce@momjian.us 292 [ + + ]: 647482 : for (i = 0; i < sp->timecnt; ++i)
293 : : {
2939 tgl@sss.pgh.pa.us 294 : 628810 : int64 at
295 [ - + ]: 628810 : = stored == 4 ? detzcode(p) : detzcode64(p);
296 : :
2396 297 : 628810 : sp->types[i] = at <= TIME_T_MAX;
2939 298 [ + - ]: 628810 : if (sp->types[i])
299 : : {
300 : 628810 : pg_time_t attime
301 : : = ((TYPE_SIGNED(pg_time_t) ? at < TIME_T_MIN : at < 0)
302 : : ? TIME_T_MIN : at);
303 : :
304 [ + + - + ]: 628810 : if (timecnt && attime <= sp->ats[timecnt - 1])
305 : : {
2939 tgl@sss.pgh.pa.us 306 [ # # ]:UBC 0 : if (attime < sp->ats[timecnt - 1])
307 : 0 : return EINVAL;
308 : 0 : sp->types[i - 1] = 0;
309 : 0 : timecnt--;
310 : : }
2939 tgl@sss.pgh.pa.us 311 :CBC 628810 : sp->ats[timecnt++] = attime;
312 : : }
5902 313 : 628810 : p += stored;
314 : : }
315 : :
2939 316 : 18672 : timecnt = 0;
7268 bruce@momjian.us 317 [ + + ]: 647482 : for (i = 0; i < sp->timecnt; ++i)
318 : : {
2939 tgl@sss.pgh.pa.us 319 : 628810 : unsigned char typ = *p++;
320 : :
321 [ - + ]: 628810 : if (sp->typecnt <= typ)
2939 tgl@sss.pgh.pa.us 322 :UBC 0 : return EINVAL;
2939 tgl@sss.pgh.pa.us 323 [ + - ]:CBC 628810 : if (sp->types[i])
324 : 628810 : sp->types[timecnt++] = typ;
325 : : }
326 : 18672 : sp->timecnt = timecnt;
7268 bruce@momjian.us 327 [ + + ]: 67656 : for (i = 0; i < sp->typecnt; ++i)
328 : : {
329 : : struct ttinfo *ttisp;
330 : : unsigned char isdst,
331 : : desigidx;
332 : :
7289 333 : 48984 : ttisp = &sp->ttis[i];
1733 tgl@sss.pgh.pa.us 334 : 48984 : ttisp->tt_utoff = detzcode(p);
7289 bruce@momjian.us 335 : 48984 : p += 4;
2939 tgl@sss.pgh.pa.us 336 : 48984 : isdst = *p++;
337 [ - + ]: 48984 : if (!(isdst < 2))
2939 tgl@sss.pgh.pa.us 338 :UBC 0 : return EINVAL;
2939 tgl@sss.pgh.pa.us 339 :CBC 48984 : ttisp->tt_isdst = isdst;
1733 340 : 48984 : desigidx = *p++;
341 [ - + ]: 48984 : if (!(desigidx < sp->charcnt))
2939 tgl@sss.pgh.pa.us 342 :UBC 0 : return EINVAL;
1733 tgl@sss.pgh.pa.us 343 :CBC 48984 : ttisp->tt_desigidx = desigidx;
344 : : }
7289 bruce@momjian.us 345 [ + + ]: 183699 : for (i = 0; i < sp->charcnt; ++i)
346 : 165027 : sp->chars[i] = *p++;
347 : 18672 : sp->chars[i] = '\0'; /* ensure '\0' at end */
348 : :
349 : : /* Read leap seconds, discarding those out of pg_time_t range. */
2939 tgl@sss.pgh.pa.us 350 : 18672 : leapcnt = 0;
7268 bruce@momjian.us 351 [ - + ]: 18672 : for (i = 0; i < sp->leapcnt; ++i)
352 : : {
2939 tgl@sss.pgh.pa.us 353 [ # # ]:UBC 0 : int64 tr = stored == 4 ? detzcode(p) : detzcode64(p);
354 : 0 : int32 corr = detzcode(p + stored);
355 : :
356 : 0 : p += stored + 4;
357 : : /* Leap seconds cannot occur before the Epoch. */
2396 358 [ # # ]: 0 : if (tr < 0)
359 : 0 : return EINVAL;
360 : : if (tr <= TIME_T_MAX)
361 : : {
362 : : /*
363 : : * Leap seconds cannot occur more than once per UTC month, and
364 : : * UTC months are at least 28 days long (minus 1 second for a
365 : : * negative leap second). Each leap second's correction must
366 : : * differ from the previous one's by 1 second.
367 : : */
368 [ # # ]: 0 : if (tr - prevtr < 28 * SECSPERDAY - 1
369 [ # # # # ]: 0 : || (corr != prevcorr - 1 && corr != prevcorr + 1))
370 : 0 : return EINVAL;
371 : 0 : sp->lsis[leapcnt].ls_trans = prevtr = tr;
372 : 0 : sp->lsis[leapcnt].ls_corr = prevcorr = corr;
2939 373 : 0 : leapcnt++;
374 : : }
375 : : }
2939 tgl@sss.pgh.pa.us 376 :CBC 18672 : sp->leapcnt = leapcnt;
377 : :
7268 bruce@momjian.us 378 [ + + ]: 67656 : for (i = 0; i < sp->typecnt; ++i)
379 : : {
380 : : struct ttinfo *ttisp;
381 : :
7289 382 : 48984 : ttisp = &sp->ttis[i];
383 [ + - ]: 48984 : if (ttisstdcnt == 0)
2939 tgl@sss.pgh.pa.us 384 : 48984 : ttisp->tt_ttisstd = false;
385 : : else
386 : : {
2939 tgl@sss.pgh.pa.us 387 [ # # # # ]:UBC 0 : if (*p != true && *p != false)
388 : 0 : return EINVAL;
7289 bruce@momjian.us 389 : 0 : ttisp->tt_ttisstd = *p++;
390 : : }
391 : : }
7268 bruce@momjian.us 392 [ + + ]:CBC 67656 : for (i = 0; i < sp->typecnt; ++i)
393 : : {
394 : : struct ttinfo *ttisp;
395 : :
7289 396 : 48984 : ttisp = &sp->ttis[i];
1733 tgl@sss.pgh.pa.us 397 [ + - ]: 48984 : if (ttisutcnt == 0)
398 : 48984 : ttisp->tt_ttisut = false;
399 : : else
400 : : {
2939 tgl@sss.pgh.pa.us 401 [ # # # # ]:UBC 0 : if (*p != true && *p != false)
402 : 0 : return EINVAL;
1733 403 : 0 : ttisp->tt_ttisut = *p++;
404 : : }
405 : : }
406 : :
407 : : /*
408 : : * If this is an old file, we're done.
409 : : */
2939 tgl@sss.pgh.pa.us 410 [ - + ]:CBC 18672 : if (up->tzhead.tzh_version[0] == '\0')
5902 tgl@sss.pgh.pa.us 411 :UBC 0 : break;
2939 tgl@sss.pgh.pa.us 412 :CBC 18672 : nread -= p - up->buf;
413 : 18672 : memmove(up->buf, p, nread);
414 : : }
5902 415 [ + - + - ]: 9336 : if (doextend && nread > 2 &&
2939 416 [ + - + - ]: 9336 : up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
5902 417 [ + - ]: 9336 : sp->typecnt + 2 <= TZ_MAX_TYPES)
418 : : {
2939 419 : 9336 : struct state *ts = &lsp->u.st;
420 : :
421 : 9336 : up->buf[nread - 1] = '\0';
2004 422 [ + - ]: 9336 : if (tzparse(&up->buf[1], ts, false))
423 : : {
424 : : /*
425 : : * Attempt to reuse existing abbreviations. Without this,
426 : : * America/Anchorage would be right on the edge after 2037 when
427 : : * TZ_MAX_CHARS is 50, as sp->charcnt equals 40 (for LMT AST AWT
428 : : * APT AHST AHDT YST AKDT AKST) and ts->charcnt equals 10 (for
429 : : * AKST AKDT). Reusing means sp->charcnt can stay 40 in this
430 : : * example.
431 : : */
2939 432 : 9336 : int gotabbr = 0;
433 : 9336 : int charcnt = sp->charcnt;
434 : :
2004 435 [ + + ]: 24473 : for (i = 0; i < ts->typecnt; i++)
436 : : {
1733 437 : 15137 : char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx;
438 : : int j;
439 : :
2939 440 [ + + ]: 103673 : for (j = 0; j < charcnt; j++)
441 [ + + ]: 103641 : if (strcmp(sp->chars + j, tsabbr) == 0)
442 : : {
1733 443 : 15105 : ts->ttis[i].tt_desigidx = j;
2939 444 : 15105 : gotabbr++;
445 : 15105 : break;
446 : : }
447 [ + + ]: 15137 : if (!(j < charcnt))
448 : : {
449 : 32 : int tsabbrlen = strlen(tsabbr);
450 : :
451 [ + - ]: 32 : if (j + tsabbrlen < TZ_MAX_CHARS)
452 : : {
453 : 32 : strcpy(sp->chars + j, tsabbr);
454 : 32 : charcnt = j + tsabbrlen + 1;
1733 455 : 32 : ts->ttis[i].tt_desigidx = j;
2939 456 : 32 : gotabbr++;
457 : : }
458 : : }
459 : : }
2004 460 [ + - ]: 9336 : if (gotabbr == ts->typecnt)
461 : : {
2939 462 : 9336 : sp->charcnt = charcnt;
463 : :
464 : : /*
465 : : * Ignore any trailing, no-op transitions generated by zic as
466 : : * they don't help here and can run afoul of bugs in zic 2016j
467 : : * or earlier.
468 : : */
2541 469 : 9336 : while (1 < sp->timecnt
470 [ + + ]: 9352 : && (sp->types[sp->timecnt - 1]
471 [ + + ]: 8360 : == sp->types[sp->timecnt - 2]))
472 : 16 : sp->timecnt--;
473 : :
2939 474 [ + + ]: 2759720 : for (i = 0; i < ts->timecnt; i++)
2004 475 [ + - ]: 2756185 : if (sp->timecnt == 0
1397 476 : 5512370 : || (sp->ats[sp->timecnt - 1]
477 [ + + ]: 2756185 : < ts->ats[i] + leapcorr(sp, ts->ats[i])))
478 : : break;
2939 479 : 9336 : while (i < ts->timecnt
480 [ + + + - ]: 8860952 : && sp->timecnt < TZ_MAX_TIMES)
481 : : {
1397 482 : 8851616 : sp->ats[sp->timecnt]
483 : 8851616 : = ts->ats[i] + leapcorr(sp, ts->ats[i]);
2939 484 : 8851616 : sp->types[sp->timecnt] = (sp->typecnt
485 : 8851616 : + ts->types[i]);
486 : 8851616 : sp->timecnt++;
487 : 8851616 : i++;
488 : : }
2004 489 [ + + ]: 24473 : for (i = 0; i < ts->typecnt; i++)
490 : 15137 : sp->ttis[sp->typecnt++] = ts->ttis[i];
491 : : }
492 : : }
493 : : }
494 [ - + ]: 9336 : if (sp->typecnt == 0)
2004 tgl@sss.pgh.pa.us 495 :UBC 0 : return EINVAL;
5148 tgl@sss.pgh.pa.us 496 [ + + ]:CBC 9336 : if (sp->timecnt > 1)
497 : : {
498 [ + + ]: 9480050 : for (i = 1; i < sp->timecnt; ++i)
499 [ + + - + ]: 13457378 : if (typesequiv(sp, sp->types[i], sp->types[0]) &&
500 : 3985672 : differ_by_repeat(sp->ats[i], sp->ats[0]))
501 : : {
2939 tgl@sss.pgh.pa.us 502 :UBC 0 : sp->goback = true;
5148 503 : 0 : break;
504 : : }
5148 tgl@sss.pgh.pa.us 505 [ + + ]:CBC 4722889 : for (i = sp->timecnt - 2; i >= 0; --i)
506 [ + + ]: 4720346 : if (typesequiv(sp, sp->types[sp->timecnt - 1],
507 [ + + ]: 7064671 : sp->types[i]) &&
508 : 2344325 : differ_by_repeat(sp->ats[sp->timecnt - 1],
509 : : sp->ats[i]))
510 : : {
2939 511 : 5801 : sp->goahead = true;
512 : 5801 : break;
513 : : }
514 : : }
515 : :
516 : : /*
517 : : * Infer sp->defaulttype from the data. Although this default type is
518 : : * always zero for data from recent tzdb releases, things are trickier for
519 : : * data from tzdb 2018e or earlier.
520 : : *
521 : : * The first set of heuristics work around bugs in 32-bit data generated
522 : : * by tzdb 2013c or earlier. The workaround is for zones like
523 : : * Australia/Macquarie where timestamps before the first transition have a
524 : : * time type that is not the earliest standard-time type. See:
525 : : * https://mm.icann.org/pipermail/tz/2013-May/019368.html
526 : : */
527 : :
528 : : /*
529 : : * If type 0 is unused in transitions, it's the type to use for early
530 : : * times.
531 : : */
532 [ + + ]: 4108040 : for (i = 0; i < sp->timecnt; ++i)
533 [ + + ]: 4102141 : if (sp->types[i] == 0)
534 : 3437 : break;
535 [ + + ]: 9336 : i = i < sp->timecnt ? -1 : 0;
536 : :
537 : : /*
538 : : * Absent the above, if there are transition times and the first
539 : : * transition is to a daylight time find the standard type less than and
540 : : * closest to the type of the first transition.
541 : : */
542 [ + + + - : 9336 : if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst)
+ + ]
543 : : {
544 : 3314 : i = sp->types[0];
545 [ + - ]: 3314 : while (--i >= 0)
546 [ + - ]: 3314 : if (!sp->ttis[i].tt_isdst)
547 : 3314 : break;
548 : : }
549 : :
550 : : /*
551 : : * The next heuristics are for data generated by tzdb 2018e or earlier,
552 : : * for zones like EST5EDT where the first transition is to DST.
553 : : */
554 : :
555 : : /*
556 : : * If no result yet, find the first standard type. If there is none, punt
557 : : * to type zero.
558 : : */
559 [ + + ]: 9336 : if (i < 0)
560 : : {
561 : 123 : i = 0;
562 [ - + ]: 123 : while (sp->ttis[i].tt_isdst)
2939 tgl@sss.pgh.pa.us 563 [ # # ]:UBC 0 : if (++i >= sp->typecnt)
564 : : {
565 : 0 : i = 0;
5148 566 : 0 : break;
567 : : }
568 : : }
569 : :
570 : : /*
571 : : * A simple 'sp->defaulttype = 0;' would suffice here if we didn't have to
572 : : * worry about 2018e-or-earlier data. Even simpler would be to remove the
573 : : * defaulttype member and just use 0 in its place.
574 : : */
2939 tgl@sss.pgh.pa.us 575 :CBC 9336 : sp->defaulttype = i;
576 : :
7289 bruce@momjian.us 577 : 9336 : return 0;
578 : : }
579 : :
580 : : /* Load tz data from the file named NAME into *SP. Read extended
581 : : * format if DOEXTEND. Return 0 on success, an errno value on failure.
582 : : * PG: If "canonname" is not NULL, then on success the canonical spelling of
583 : : * given name is stored there (the buffer must be > TZ_STRLEN_MAX bytes!).
584 : : */
585 : : int
2489 tgl@sss.pgh.pa.us 586 : 9630 : tzload(const char *name, char *canonname, struct state *sp, bool doextend)
587 : : {
2838 588 : 9630 : union local_storage *lsp = malloc(sizeof *lsp);
589 : :
590 [ - + ]: 9630 : if (!lsp)
2838 tgl@sss.pgh.pa.us 591 :UBC 0 : return errno;
592 : : else
593 : : {
2838 tgl@sss.pgh.pa.us 594 :CBC 9630 : int err = tzloadbody(name, canonname, sp, doextend, lsp);
595 : :
596 : 9630 : free(lsp);
597 : 9630 : return err;
598 : : }
599 : : }
600 : :
601 : : static bool
2489 602 : 14192052 : typesequiv(const struct state *sp, int a, int b)
603 : : {
604 : : bool result;
605 : :
5902 606 [ + - + - ]: 14192052 : if (sp == NULL ||
607 [ + - + - ]: 14192052 : a < 0 || a >= sp->typecnt ||
608 [ - + ]: 14192052 : b < 0 || b >= sp->typecnt)
2939 tgl@sss.pgh.pa.us 609 :UBC 0 : result = false;
610 : : else
611 : : {
5902 tgl@sss.pgh.pa.us 612 :CBC 14192052 : const struct ttinfo *ap = &sp->ttis[a];
613 : 14192052 : const struct ttinfo *bp = &sp->ttis[b];
614 : :
1733 615 : 14192052 : result = (ap->tt_utoff == bp->tt_utoff
616 [ + + ]: 6389216 : && ap->tt_isdst == bp->tt_isdst
617 [ + - ]: 6350372 : && ap->tt_ttisstd == bp->tt_ttisstd
618 [ + - ]: 6350372 : && ap->tt_ttisut == bp->tt_ttisut
619 [ + + ]: 20581268 : && (strcmp(&sp->chars[ap->tt_desigidx],
620 [ + + ]: 6350372 : &sp->chars[bp->tt_desigidx])
621 : : == 0));
622 : : }
5902 623 : 14192052 : return result;
624 : : }
625 : :
626 : : static const int mon_lengths[2][MONSPERYEAR] = {
627 : : {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
628 : : {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
629 : : };
630 : :
631 : : static const int year_lengths[2] = {
632 : : DAYSPERNYEAR, DAYSPERLYEAR
633 : : };
634 : :
635 : : /*
636 : : * Given a pointer into a timezone string, scan until a character that is not
637 : : * a valid character in a time zone abbreviation is found.
638 : : * Return a pointer to that character.
639 : : */
640 : :
641 : : static const char *
6873 neilc@samurai.com 642 : 13313 : getzname(const char *strp)
643 : : {
644 : : char c;
645 : :
7289 bruce@momjian.us 646 [ + + + + : 56913 : while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
+ + + + +
+ ]
647 : : c != '+')
7268 648 : 43600 : ++strp;
7289 649 : 13313 : return strp;
650 : : }
651 : :
652 : : /*
653 : : * Given a pointer into an extended timezone string, scan until the ending
654 : : * delimiter of the time zone abbreviation is located.
655 : : * Return a pointer to the delimiter.
656 : : *
657 : : * As with getzname above, the legal character set is actually quite
658 : : * restricted, with other characters producing undefined results.
659 : : * We don't do any checking here; checking is done later in common-case code.
660 : : */
661 : :
662 : : static const char *
2004 tgl@sss.pgh.pa.us 663 : 2121 : getqzname(const char *strp, const int delim)
664 : : {
665 : : int c;
666 : :
5902 667 [ + - + + ]: 8795 : while ((c = *strp) != '\0' && c != delim)
668 : 6674 : ++strp;
669 : 2121 : return strp;
670 : : }
671 : :
672 : : /*
673 : : * Given a pointer into a timezone string, extract a number from that string.
674 : : * Check that the number is within a specified range; if it is not, return
675 : : * NULL.
676 : : * Otherwise, return a pointer to the first character not part of the number.
677 : : */
678 : :
679 : : static const char *
2004 680 : 45875 : getnum(const char *strp, int *const nump, const int min, const int max)
681 : : {
682 : : char c;
683 : : int num;
684 : :
7289 bruce@momjian.us 685 [ + - - + ]: 45875 : if (strp == NULL || !is_digit(c = *strp))
7289 bruce@momjian.us 686 :UBC 0 : return NULL;
7289 bruce@momjian.us 687 :CBC 45875 : num = 0;
688 : : do
689 : : {
690 : 52809 : num = num * 10 + (c - '0');
691 [ - + ]: 52809 : if (num > max)
7268 bruce@momjian.us 692 :UBC 0 : return NULL; /* illegal value */
7289 bruce@momjian.us 693 :CBC 52809 : c = *++strp;
694 [ + + ]: 52809 : } while (is_digit(c));
695 [ - + ]: 45875 : if (num < min)
7268 bruce@momjian.us 696 :UBC 0 : return NULL; /* illegal value */
7289 bruce@momjian.us 697 :CBC 45875 : *nump = num;
698 : 45875 : return strp;
699 : : }
700 : :
701 : : /*
702 : : * Given a pointer into a timezone string, extract a number of seconds,
703 : : * in hh[:mm[:ss]] form, from the string.
704 : : * If any error occurs, return NULL.
705 : : * Otherwise, return a pointer to the first character not part of the number
706 : : * of seconds.
707 : : */
708 : :
709 : : static const char *
2004 tgl@sss.pgh.pa.us 710 : 10762 : getsecs(const char *strp, int32 *const secsp)
711 : : {
712 : : int num;
713 : :
714 : : /*
715 : : * 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
716 : : * "M10.4.6/26", which does not conform to Posix, but which specifies the
717 : : * equivalent of "02:00 on the first Sunday on or after 23 Oct".
718 : : */
7289 bruce@momjian.us 719 : 10762 : strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
720 [ - + ]: 10762 : if (strp == NULL)
7289 bruce@momjian.us 721 :UBC 0 : return NULL;
2939 tgl@sss.pgh.pa.us 722 :CBC 10762 : *secsp = num * (int32) SECSPERHOUR;
7268 bruce@momjian.us 723 [ + + ]: 10762 : if (*strp == ':')
724 : : {
7289 725 : 289 : ++strp;
726 : 289 : strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
727 [ - + ]: 289 : if (strp == NULL)
7289 bruce@momjian.us 728 :UBC 0 : return NULL;
7289 bruce@momjian.us 729 :CBC 289 : *secsp += num * SECSPERMIN;
7268 730 [ - + ]: 289 : if (*strp == ':')
731 : : {
7289 bruce@momjian.us 732 :UBC 0 : ++strp;
733 : : /* 'SECSPERMIN' allows for leap seconds. */
734 : 0 : strp = getnum(strp, &num, 0, SECSPERMIN);
735 [ # # ]: 0 : if (strp == NULL)
736 : 0 : return NULL;
737 : 0 : *secsp += num;
738 : : }
739 : : }
7289 bruce@momjian.us 740 :CBC 10762 : return strp;
741 : : }
742 : :
743 : : /*
744 : : * Given a pointer into a timezone string, extract an offset, in
745 : : * [+-]hh[:mm[:ss]] form, from the string.
746 : : * If any error occurs, return NULL.
747 : : * Otherwise, return a pointer to the first character not part of the time.
748 : : */
749 : :
750 : : static const char *
2004 tgl@sss.pgh.pa.us 751 : 10762 : getoffset(const char *strp, int32 *const offsetp)
752 : : {
2939 753 : 10762 : bool neg = false;
754 : :
7268 bruce@momjian.us 755 [ + + ]: 10762 : if (*strp == '-')
756 : : {
2939 tgl@sss.pgh.pa.us 757 : 2697 : neg = true;
7289 bruce@momjian.us 758 : 2697 : ++strp;
759 : : }
7268 760 [ + + ]: 8065 : else if (*strp == '+')
7289 761 : 70 : ++strp;
762 : 10762 : strp = getsecs(strp, offsetp);
763 [ - + ]: 10762 : if (strp == NULL)
7268 bruce@momjian.us 764 :UBC 0 : return NULL; /* illegal time */
7289 bruce@momjian.us 765 [ + + ]:CBC 10762 : if (neg)
766 : 2697 : *offsetp = -*offsetp;
767 : 10762 : return strp;
768 : : }
769 : :
770 : : /*
771 : : * Given a pointer into a timezone string, extract a rule in the form
772 : : * date[/time]. See POSIX section 8 for the format of "date" and "time".
773 : : * If a valid rule is not found, return NULL.
774 : : * Otherwise, return a pointer to the first character not part of the rule.
775 : : */
776 : :
777 : : static const char *
2004 tgl@sss.pgh.pa.us 778 : 11608 : getrule(const char *strp, struct rule *const rulep)
779 : : {
7268 bruce@momjian.us 780 [ - + ]: 11608 : if (*strp == 'J')
781 : : {
782 : : /*
783 : : * Julian day.
784 : : */
7289 bruce@momjian.us 785 :UBC 0 : rulep->r_type = JULIAN_DAY;
786 : 0 : ++strp;
787 : 0 : strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
788 : : }
7268 bruce@momjian.us 789 [ + - ]:CBC 11608 : else if (*strp == 'M')
790 : : {
791 : : /*
792 : : * Month, week, day.
793 : : */
7289 794 : 11608 : rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
795 : 11608 : ++strp;
796 : 11608 : strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
797 [ - + ]: 11608 : if (strp == NULL)
7289 bruce@momjian.us 798 :UBC 0 : return NULL;
7289 bruce@momjian.us 799 [ - + ]:CBC 11608 : if (*strp++ != '.')
7289 bruce@momjian.us 800 :UBC 0 : return NULL;
7289 bruce@momjian.us 801 :CBC 11608 : strp = getnum(strp, &rulep->r_week, 1, 5);
802 [ - + ]: 11608 : if (strp == NULL)
7289 bruce@momjian.us 803 :UBC 0 : return NULL;
7289 bruce@momjian.us 804 [ - + ]:CBC 11608 : if (*strp++ != '.')
7289 bruce@momjian.us 805 :UBC 0 : return NULL;
7289 bruce@momjian.us 806 :CBC 11608 : strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
807 : : }
7268 bruce@momjian.us 808 [ # # ]:UBC 0 : else if (is_digit(*strp))
809 : : {
810 : : /*
811 : : * Day of year.
812 : : */
7289 813 : 0 : rulep->r_type = DAY_OF_YEAR;
814 : 0 : strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
815 : : }
816 : : else
7268 817 : 0 : return NULL; /* invalid format */
7289 bruce@momjian.us 818 [ - + ]:CBC 11608 : if (strp == NULL)
7289 bruce@momjian.us 819 :UBC 0 : return NULL;
7268 bruce@momjian.us 820 [ + + ]:CBC 11608 : if (*strp == '/')
821 : : {
822 : : /*
823 : : * Time specified.
824 : : */
7289 825 : 1217 : ++strp;
2939 tgl@sss.pgh.pa.us 826 : 1217 : strp = getoffset(strp, &rulep->r_time);
827 : : }
828 : : else
2489 829 : 10391 : rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
7289 bruce@momjian.us 830 : 11608 : return strp;
831 : : }
832 : :
833 : : /*
834 : : * Given a year, a rule, and the offset from UT at the time that rule takes
835 : : * effect, calculate the year-relative time that rule takes effect.
836 : : */
837 : :
838 : : static int32
2004 tgl@sss.pgh.pa.us 839 : 11619608 : transtime(const int year, const struct rule *const rulep,
840 : : const int32 offset)
841 : : {
842 : : bool leapyear;
843 : : int32 value;
844 : : int i;
845 : : int d,
846 : : m1,
847 : : yy0,
848 : : yy1,
849 : : yy2,
850 : : dow;
851 : :
2939 852 : 11619608 : INITIALIZE(value);
7289 bruce@momjian.us 853 [ + + + + : 11619608 : leapyear = isleap(year);
+ + ]
7268 854 [ - - + - ]: 11619608 : switch (rulep->r_type)
855 : : {
856 : :
7268 bruce@momjian.us 857 :UBC 0 : case JULIAN_DAY:
858 : :
859 : : /*
860 : : * Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
861 : : * years. In non-leap years, or if the day number is 59 or less,
862 : : * just add SECSPERDAY times the day number-1 to the time of
863 : : * January 1, midnight, to get the day.
864 : : */
2939 tgl@sss.pgh.pa.us 865 : 0 : value = (rulep->r_day - 1) * SECSPERDAY;
7268 bruce@momjian.us 866 [ # # # # ]: 0 : if (leapyear && rulep->r_day >= 60)
867 : 0 : value += SECSPERDAY;
868 : 0 : break;
869 : :
870 : 0 : case DAY_OF_YEAR:
871 : :
872 : : /*
873 : : * n - day of year. Just add SECSPERDAY times the day number to
874 : : * the time of January 1, midnight, to get the day.
875 : : */
2939 tgl@sss.pgh.pa.us 876 : 0 : value = rulep->r_day * SECSPERDAY;
7268 bruce@momjian.us 877 : 0 : break;
878 : :
7268 bruce@momjian.us 879 :CBC 11619608 : case MONTH_NTH_DAY_OF_WEEK:
880 : :
881 : : /*
882 : : * Mm.n.d - nth "dth day" of month m.
883 : : */
884 : :
885 : : /*
886 : : * Use Zeller's Congruence to get day-of-week of first day of
887 : : * month.
888 : : */
889 : 11619608 : m1 = (rulep->r_mon + 9) % 12 + 1;
890 [ - + ]: 11619608 : yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
891 : 11619608 : yy1 = yy0 / 100;
892 : 11619608 : yy2 = yy0 % 100;
893 : 11619608 : dow = ((26 * m1 - 2) / 10 +
894 : 11619608 : 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
895 [ + + ]: 11619608 : if (dow < 0)
896 : 2182971 : dow += DAYSPERWEEK;
897 : :
898 : : /*
899 : : * "dow" is the day-of-week of the first day of the month. Get the
900 : : * day-of-month (zero-origin) of the first "dow" day of the month.
901 : : */
902 : 11619608 : d = rulep->r_day - dow;
903 [ + + ]: 11619608 : if (d < 0)
904 : 9812549 : d += DAYSPERWEEK;
905 [ + + ]: 21394564 : for (i = 1; i < rulep->r_week; ++i)
906 : : {
907 : 10569559 : if (d + DAYSPERWEEK >=
2939 tgl@sss.pgh.pa.us 908 [ + + ]: 10569559 : mon_lengths[(int) leapyear][rulep->r_mon - 1])
7289 bruce@momjian.us 909 : 794603 : break;
7268 910 : 9774956 : d += DAYSPERWEEK;
911 : : }
912 : :
913 : : /*
914 : : * "d" is the day-of-month (zero-origin) of the day we want.
915 : : */
2939 tgl@sss.pgh.pa.us 916 : 11619608 : value = d * SECSPERDAY;
917 [ + + ]: 80567487 : for (i = 0; i < rulep->r_mon - 1; ++i)
918 : 68947879 : value += mon_lengths[(int) leapyear][i] * SECSPERDAY;
7268 bruce@momjian.us 919 : 11619608 : break;
920 : : }
921 : :
922 : : /*
923 : : * "value" is the year-relative time of 00:00:00 UT on the day in
924 : : * question. To get the year-relative time of the specified local time on
925 : : * that day, add the transition time and the current offset from UT.
926 : : */
7289 927 : 11619608 : return value + rulep->r_time + offset;
928 : : }
929 : :
930 : : /*
931 : : * Given a POSIX section 8-style TZ string, fill in the rule tables as
932 : : * appropriate.
933 : : * Returns true on success, false on failure.
934 : : */
935 : : bool
2489 tgl@sss.pgh.pa.us 936 : 10558 : tzparse(const char *name, struct state *sp, bool lastditch)
937 : : {
938 : : const char *stdname;
7268 bruce@momjian.us 939 : 10558 : const char *dstname = NULL;
940 : : size_t stdlen;
941 : : size_t dstlen;
942 : : size_t charcnt;
943 : : int32 stdoffset;
944 : : int32 dstoffset;
945 : : char *cp;
946 : : bool load_ok;
947 : :
7289 948 : 10558 : stdname = name;
7268 949 [ + + ]: 10558 : if (lastditch)
950 : : {
951 : : /* Unlike IANA, don't assume name is exactly "GMT" */
7289 952 : 928 : stdlen = strlen(name); /* length of standard zone name */
953 : 928 : name += stdlen;
954 : 928 : stdoffset = 0;
955 : : }
956 : : else
957 : : {
5902 tgl@sss.pgh.pa.us 958 [ + + ]: 9630 : if (*name == '<')
959 : : {
960 : 1981 : name++;
961 : 1981 : stdname = name;
962 : 1981 : name = getqzname(name, '>');
963 [ - + ]: 1981 : if (*name != '>')
2939 tgl@sss.pgh.pa.us 964 :UBC 0 : return false;
5902 tgl@sss.pgh.pa.us 965 :CBC 1981 : stdlen = name - stdname;
966 : 1981 : name++;
967 : : }
968 : : else
969 : : {
970 : 7649 : name = getzname(name);
971 : 7649 : stdlen = name - stdname;
972 : : }
2939 973 [ + + ]: 9630 : if (*name == '\0') /* we allow empty STD abbrev, unlike IANA */
974 : 128 : return false;
7289 bruce@momjian.us 975 : 9502 : name = getoffset(name, &stdoffset);
976 [ - + ]: 9502 : if (name == NULL)
2939 tgl@sss.pgh.pa.us 977 :UBC 0 : return false;
978 : : }
2006 tgl@sss.pgh.pa.us 979 :CBC 10430 : charcnt = stdlen + 1;
980 [ - + ]: 10430 : if (sizeof sp->chars < charcnt)
2006 tgl@sss.pgh.pa.us 981 :UBC 0 : return false;
982 : :
983 : : /*
984 : : * The IANA code always tries to tzload(TZDEFRULES) here. We do not want
985 : : * to do that; it would be bad news in the lastditch case, where we can't
986 : : * assume pg_open_tzfile() is sane yet. Moreover, if we did load it and
987 : : * it contains leap-second-dependent info, that would cause problems too.
988 : : * Finally, IANA has deprecated the TZDEFRULES feature, so it presumably
989 : : * will die at some point. Desupporting it now seems like good
990 : : * future-proofing.
991 : : */
1385 tgl@sss.pgh.pa.us 992 :CBC 10430 : load_ok = false;
2006 993 : 10430 : sp->goback = sp->goahead = false; /* simulate failed tzload() */
994 : 10430 : sp->leapcnt = 0; /* intentionally assume no leap seconds */
995 : :
7268 bruce@momjian.us 996 [ + + ]: 10430 : if (*name != '\0')
997 : : {
5902 tgl@sss.pgh.pa.us 998 [ + + ]: 5804 : if (*name == '<')
999 : : {
1000 : 140 : dstname = ++name;
1001 : 140 : name = getqzname(name, '>');
1002 [ - + ]: 140 : if (*name != '>')
2939 tgl@sss.pgh.pa.us 1003 :UBC 0 : return false;
5902 tgl@sss.pgh.pa.us 1004 :CBC 140 : dstlen = name - dstname;
1005 : 140 : name++;
1006 : : }
1007 : : else
1008 : : {
1009 : 5664 : dstname = name;
1010 : 5664 : name = getzname(name);
2004 1011 : 5664 : dstlen = name - dstname; /* length of DST abbr. */
1012 : : }
2939 1013 [ - + ]: 5804 : if (!dstlen)
2939 tgl@sss.pgh.pa.us 1014 :UBC 0 : return false;
2939 tgl@sss.pgh.pa.us 1015 :CBC 5804 : charcnt += dstlen + 1;
1016 [ - + ]: 5804 : if (sizeof sp->chars < charcnt)
2939 tgl@sss.pgh.pa.us 1017 :UBC 0 : return false;
7268 bruce@momjian.us 1018 [ + - + + :CBC 5804 : if (*name != '\0' && *name != ',' && *name != ';')
+ - ]
1019 : : {
7289 1020 : 43 : name = getoffset(name, &dstoffset);
1021 [ - + ]: 43 : if (name == NULL)
2939 tgl@sss.pgh.pa.us 1022 :UBC 0 : return false;
1023 : : }
1024 : : else
7268 bruce@momjian.us 1025 :CBC 5761 : dstoffset = stdoffset - SECSPERHOUR;
1385 tgl@sss.pgh.pa.us 1026 [ - + - - ]: 5804 : if (*name == '\0' && !load_ok)
1385 tgl@sss.pgh.pa.us 1027 :UBC 0 : name = TZDEFRULESTRING;
7268 bruce@momjian.us 1028 [ - + - - ]:CBC 5804 : if (*name == ',' || *name == ';')
1029 : 5804 : {
1030 : : struct rule start;
1031 : : struct rule end;
1032 : : int year;
1033 : : int yearlim;
1034 : : int timecnt;
1035 : : pg_time_t janfirst;
2541 tgl@sss.pgh.pa.us 1036 : 5804 : int32 janoffset = 0;
1037 : : int yearbeg;
1038 : :
7289 bruce@momjian.us 1039 : 5804 : ++name;
1040 [ - + ]: 5804 : if ((name = getrule(name, &start)) == NULL)
2939 tgl@sss.pgh.pa.us 1041 :UBC 0 : return false;
7289 bruce@momjian.us 1042 [ - + ]:CBC 5804 : if (*name++ != ',')
2939 tgl@sss.pgh.pa.us 1043 :UBC 0 : return false;
7289 bruce@momjian.us 1044 [ - + ]:CBC 5804 : if ((name = getrule(name, &end)) == NULL)
2939 tgl@sss.pgh.pa.us 1045 :UBC 0 : return false;
7289 bruce@momjian.us 1046 [ - + ]:CBC 5804 : if (*name != '\0')
2939 tgl@sss.pgh.pa.us 1047 :UBC 0 : return false;
7289 bruce@momjian.us 1048 :CBC 5804 : sp->typecnt = 2; /* standard time and DST */
1049 : :
1050 : : /*
1051 : : * Two transitions per year, from EPOCH_YEAR forward.
1052 : : */
2004 tgl@sss.pgh.pa.us 1053 : 5804 : init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1054 : 5804 : init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
2939 1055 : 5804 : sp->defaulttype = 0;
1056 : 5804 : timecnt = 0;
7289 bruce@momjian.us 1057 : 5804 : janfirst = 0;
2541 tgl@sss.pgh.pa.us 1058 : 5804 : yearbeg = EPOCH_YEAR;
1059 : :
1060 : : do
1061 : : {
1062 : 1160800 : int32 yearsecs
1063 [ + + + + : 1160800 : = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
- + ]
1064 : :
1065 : 1160800 : yearbeg--;
1066 [ - + ]: 1160800 : if (increment_overflow_time(&janfirst, -yearsecs))
1067 : : {
2541 tgl@sss.pgh.pa.us 1068 :UBC 0 : janoffset = -yearsecs;
1069 : 0 : break;
1070 : : }
2541 tgl@sss.pgh.pa.us 1071 [ + + ]:CBC 1160800 : } while (EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
1072 : :
1073 : 5804 : yearlim = yearbeg + YEARSPERREPEAT + 1;
1074 [ + - ]: 5809804 : for (year = yearbeg; year < yearlim; year++)
1075 : : {
1076 : : int32
2939 1077 : 5809804 : starttime = transtime(year, &start, stdoffset),
1078 : 5809804 : endtime = transtime(year, &end, dstoffset);
1079 : : int32
1080 [ + + + + : 5809804 : yearsecs = (year_lengths[isleap(year)]
+ + ]
1081 : : * SECSPERDAY);
1082 : 5809804 : bool reversed = endtime < starttime;
1083 : :
1084 [ + + ]: 5809804 : if (reversed)
1085 : : {
1086 : 255255 : int32 swap = starttime;
1087 : :
1088 : 255255 : starttime = endtime;
1089 : 255255 : endtime = swap;
1090 : : }
1091 [ + + ]: 5809804 : if (reversed
1092 [ + - ]: 5554549 : || (starttime < endtime
1093 : 5554549 : && (endtime - starttime
1094 : : < (yearsecs
1095 [ + - ]: 5554549 : + (stdoffset - dstoffset)))))
1096 : : {
1097 [ + + ]: 5809804 : if (TZ_MAX_TIMES - 2 < timecnt)
1098 : 5804 : break;
1099 : 5804000 : sp->ats[timecnt] = janfirst;
2541 1100 [ + - ]: 5804000 : if (!increment_overflow_time
1101 : : (&sp->ats[timecnt],
1102 : : janoffset + starttime))
2004 1103 : 5804000 : sp->types[timecnt++] = !reversed;
2939 1104 : 5804000 : sp->ats[timecnt] = janfirst;
2541 1105 [ + - ]: 5804000 : if (!increment_overflow_time
1106 : : (&sp->ats[timecnt],
1107 : : janoffset + endtime))
1108 : : {
2004 1109 : 5804000 : sp->types[timecnt++] = reversed;
2541 1110 : 5804000 : yearlim = year + YEARSPERREPEAT + 1;
1111 : : }
1112 : : }
1113 [ - + ]: 5804000 : if (increment_overflow_time
1114 : : (&janfirst, janoffset + yearsecs))
5902 tgl@sss.pgh.pa.us 1115 :UBC 0 : break;
2541 tgl@sss.pgh.pa.us 1116 :CBC 5804000 : janoffset = 0;
1117 : : }
2939 1118 : 5804 : sp->timecnt = timecnt;
1119 [ - + ]: 5804 : if (!timecnt)
1120 : : {
2004 tgl@sss.pgh.pa.us 1121 :UBC 0 : sp->ttis[0] = sp->ttis[1];
2939 1122 : 0 : sp->typecnt = 1; /* Perpetual DST. */
1123 : : }
2541 tgl@sss.pgh.pa.us 1124 [ + - ]:CBC 5804 : else if (YEARSPERREPEAT < year - yearbeg)
1125 : 5804 : sp->goback = sp->goahead = true;
1126 : : }
1127 : : else
1128 : : {
1129 : : int32 theirstdoffset;
1130 : : int32 theirdstoffset;
1131 : : int32 theiroffset;
1132 : : bool isdst;
1133 : : int i;
1134 : : int j;
1135 : :
7289 bruce@momjian.us 1136 [ # # ]:UBC 0 : if (*name != '\0')
2939 tgl@sss.pgh.pa.us 1137 : 0 : return false;
1138 : :
1139 : : /*
1140 : : * Initial values of theirstdoffset and theirdstoffset.
1141 : : */
7289 bruce@momjian.us 1142 : 0 : theirstdoffset = 0;
7268 1143 [ # # ]: 0 : for (i = 0; i < sp->timecnt; ++i)
1144 : : {
7289 1145 : 0 : j = sp->types[i];
7268 1146 [ # # ]: 0 : if (!sp->ttis[j].tt_isdst)
1147 : : {
7289 1148 : 0 : theirstdoffset =
1733 tgl@sss.pgh.pa.us 1149 : 0 : -sp->ttis[j].tt_utoff;
7289 bruce@momjian.us 1150 : 0 : break;
1151 : : }
1152 : : }
1153 : 0 : theirdstoffset = 0;
7268 1154 [ # # ]: 0 : for (i = 0; i < sp->timecnt; ++i)
1155 : : {
7289 1156 : 0 : j = sp->types[i];
7268 1157 [ # # ]: 0 : if (sp->ttis[j].tt_isdst)
1158 : : {
7289 1159 : 0 : theirdstoffset =
1733 tgl@sss.pgh.pa.us 1160 : 0 : -sp->ttis[j].tt_utoff;
7289 bruce@momjian.us 1161 : 0 : break;
1162 : : }
1163 : : }
1164 : :
1165 : : /*
1166 : : * Initially we're assumed to be in standard time.
1167 : : */
2939 tgl@sss.pgh.pa.us 1168 : 0 : isdst = false;
7289 bruce@momjian.us 1169 : 0 : theiroffset = theirstdoffset;
1170 : :
1171 : : /*
1172 : : * Now juggle transition times and types tracking offsets as you
1173 : : * do.
1174 : : */
7268 1175 [ # # ]: 0 : for (i = 0; i < sp->timecnt; ++i)
1176 : : {
7289 1177 : 0 : j = sp->types[i];
1178 : 0 : sp->types[i] = sp->ttis[j].tt_isdst;
1733 tgl@sss.pgh.pa.us 1179 [ # # ]: 0 : if (sp->ttis[j].tt_ttisut)
1180 : : {
1181 : : /* No adjustment to transition time */
1182 : : }
1183 : : else
1184 : : {
1185 : : /*
1186 : : * If daylight saving time is in effect, and the
1187 : : * transition time was not specified as standard time, add
1188 : : * the daylight saving time offset to the transition time;
1189 : : * otherwise, add the standard time offset to the
1190 : : * transition time.
1191 : : */
1192 : : /*
1193 : : * Transitions from DST to DDST will effectively disappear
1194 : : * since POSIX provides for only one DST offset.
1195 : : */
7268 bruce@momjian.us 1196 [ # # # # ]: 0 : if (isdst && !sp->ttis[j].tt_ttisstd)
1197 : : {
7289 1198 : 0 : sp->ats[i] += dstoffset -
1199 : : theirdstoffset;
1200 : : }
1201 : : else
1202 : : {
1203 : 0 : sp->ats[i] += stdoffset -
1204 : : theirstdoffset;
1205 : : }
1206 : : }
1733 tgl@sss.pgh.pa.us 1207 : 0 : theiroffset = -sp->ttis[j].tt_utoff;
7289 bruce@momjian.us 1208 [ # # ]: 0 : if (sp->ttis[j].tt_isdst)
1209 : 0 : theirdstoffset = theiroffset;
1210 : : else
7268 1211 : 0 : theirstdoffset = theiroffset;
1212 : : }
1213 : :
1214 : : /*
1215 : : * Finally, fill in ttis.
1216 : : */
2939 tgl@sss.pgh.pa.us 1217 : 0 : init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1218 : 0 : init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
7289 bruce@momjian.us 1219 : 0 : sp->typecnt = 2;
2939 tgl@sss.pgh.pa.us 1220 : 0 : sp->defaulttype = 0;
1221 : : }
1222 : : }
1223 : : else
1224 : : {
7289 bruce@momjian.us 1225 :CBC 4626 : dstlen = 0;
1226 : 4626 : sp->typecnt = 1; /* only standard time */
1227 : 4626 : sp->timecnt = 0;
2939 tgl@sss.pgh.pa.us 1228 : 4626 : init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1229 : 4626 : sp->defaulttype = 0;
1230 : : }
1231 : 10430 : sp->charcnt = charcnt;
7289 bruce@momjian.us 1232 : 10430 : cp = sp->chars;
2939 tgl@sss.pgh.pa.us 1233 : 10430 : memcpy(cp, stdname, stdlen);
7289 bruce@momjian.us 1234 : 10430 : cp += stdlen;
1235 : 10430 : *cp++ = '\0';
7268 1236 [ + + ]: 10430 : if (dstlen != 0)
1237 : : {
2939 tgl@sss.pgh.pa.us 1238 : 5804 : memcpy(cp, dstname, dstlen);
7289 bruce@momjian.us 1239 : 5804 : *(cp + dstlen) = '\0';
1240 : : }
2939 tgl@sss.pgh.pa.us 1241 : 10430 : return true;
1242 : : }
1243 : :
1244 : : static void
2004 1245 : 174 : gmtload(struct state *const sp)
1246 : : {
2939 1247 [ - + ]: 174 : if (tzload(gmt, NULL, sp, true) != 0)
2939 tgl@sss.pgh.pa.us 1248 :UBC 0 : tzparse(gmt, sp, true);
7289 bruce@momjian.us 1249 :CBC 174 : }
1250 : :
1251 : :
1252 : : /*
1253 : : * The easy way to behave "as if no library function calls" localtime
1254 : : * is to not call it, so we drop its guts into "localsub", which can be
1255 : : * freely called. (And no, the PANS doesn't require the above behavior,
1256 : : * but it *is* desirable.)
1257 : : */
1258 : : static struct pg_tm *
2489 tgl@sss.pgh.pa.us 1259 : 959775 : localsub(struct state const *sp, pg_time_t const *timep,
1260 : : struct pg_tm *const tmp)
1261 : : {
1262 : : const struct ttinfo *ttisp;
1263 : : int i;
1264 : : struct pg_tm *result;
7255 1265 : 959775 : const pg_time_t t = *timep;
1266 : :
2939 1267 [ - + ]: 959775 : if (sp == NULL)
2939 tgl@sss.pgh.pa.us 1268 :UBC 0 : return gmtsub(timep, 0, tmp);
5902 tgl@sss.pgh.pa.us 1269 [ + + + - ]:CBC 959775 : if ((sp->goback && t < sp->ats[0]) ||
1270 [ + + + + ]: 959775 : (sp->goahead && t > sp->ats[sp->timecnt - 1]))
1271 : : {
1272 : 30 : pg_time_t newt = t;
1273 : : pg_time_t seconds;
1274 : : pg_time_t years;
1275 : :
1276 [ - + ]: 30 : if (t < sp->ats[0])
5902 tgl@sss.pgh.pa.us 1277 :UBC 0 : seconds = sp->ats[0] - t;
1278 : : else
5421 bruce@momjian.us 1279 :CBC 30 : seconds = t - sp->ats[sp->timecnt - 1];
5902 tgl@sss.pgh.pa.us 1280 : 30 : --seconds;
2939 1281 : 30 : years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
1282 : 30 : seconds = years * AVGSECSPERYEAR;
5902 1283 [ - + ]: 30 : if (t < sp->ats[0])
5902 tgl@sss.pgh.pa.us 1284 :UBC 0 : newt += seconds;
1285 : : else
5421 bruce@momjian.us 1286 :CBC 30 : newt -= seconds;
5902 tgl@sss.pgh.pa.us 1287 [ + - ]: 30 : if (newt < sp->ats[0] ||
1288 [ - + ]: 30 : newt > sp->ats[sp->timecnt - 1])
5421 bruce@momjian.us 1289 :UBC 0 : return NULL; /* "cannot happen" */
2939 tgl@sss.pgh.pa.us 1290 :CBC 30 : result = localsub(sp, &newt, tmp);
1291 [ + - ]: 30 : if (result)
1292 : : {
1293 : : int64 newy;
1294 : :
1295 : 30 : newy = result->tm_year;
5902 1296 [ - + ]: 30 : if (t < sp->ats[0])
2939 tgl@sss.pgh.pa.us 1297 :UBC 0 : newy -= years;
1298 : : else
2939 tgl@sss.pgh.pa.us 1299 :CBC 30 : newy += years;
1300 [ + - - + ]: 30 : if (!(INT_MIN <= newy && newy <= INT_MAX))
5902 tgl@sss.pgh.pa.us 1301 :UBC 0 : return NULL;
2939 tgl@sss.pgh.pa.us 1302 :CBC 30 : result->tm_year = newy;
1303 : : }
5902 1304 : 30 : return result;
1305 : : }
7268 bruce@momjian.us 1306 [ + + + + ]: 959745 : if (sp->timecnt == 0 || t < sp->ats[0])
1307 : : {
2939 tgl@sss.pgh.pa.us 1308 : 23197 : i = sp->defaulttype;
1309 : : }
1310 : : else
1311 : : {
5421 bruce@momjian.us 1312 : 936548 : int lo = 1;
1313 : 936548 : int hi = sp->timecnt;
1314 : :
5902 tgl@sss.pgh.pa.us 1315 [ + + ]: 11134337 : while (lo < hi)
1316 : : {
5421 bruce@momjian.us 1317 : 10197789 : int mid = (lo + hi) >> 1;
1318 : :
5902 tgl@sss.pgh.pa.us 1319 [ + + ]: 10197789 : if (t < sp->ats[mid])
1320 : 7337146 : hi = mid;
1321 : : else
5421 bruce@momjian.us 1322 : 2860643 : lo = mid + 1;
1323 : : }
5902 tgl@sss.pgh.pa.us 1324 : 936548 : i = (int) sp->types[lo - 1];
1325 : : }
7289 bruce@momjian.us 1326 : 959745 : ttisp = &sp->ttis[i];
1327 : :
1328 : : /*
1329 : : * To get (wrong) behavior that's compatible with System V Release 2.0
1330 : : * you'd replace the statement below with t += ttisp->tt_utoff;
1331 : : * timesub(&t, 0L, sp, tmp);
1332 : : */
1733 tgl@sss.pgh.pa.us 1333 : 959745 : result = timesub(&t, ttisp->tt_utoff, sp, tmp);
2939 1334 [ + - ]: 959745 : if (result)
1335 : : {
1336 : 959745 : result->tm_isdst = ttisp->tt_isdst;
1733 1337 : 959745 : result->tm_zone = unconstify(char *, &sp->chars[ttisp->tt_desigidx]);
1338 : : }
5902 1339 : 959745 : return result;
1340 : : }
1341 : :
1342 : :
1343 : : struct pg_tm *
6935 bruce@momjian.us 1344 : 959745 : pg_localtime(const pg_time_t *timep, const pg_tz *tz)
1345 : : {
2939 tgl@sss.pgh.pa.us 1346 : 959745 : return localsub(&tz->state, timep, &tm);
1347 : : }
1348 : :
1349 : :
1350 : : /*
1351 : : * gmtsub is to gmtime as localsub is to localtime.
1352 : : *
1353 : : * Except we have a private "struct state" for GMT, so no sp is passed in.
1354 : : */
1355 : :
1356 : : static struct pg_tm *
2004 1357 : 159471 : gmtsub(pg_time_t const *timep, int32 offset,
1358 : : struct pg_tm *tmp)
1359 : : {
1360 : : struct pg_tm *result;
1361 : :
1362 : : /* GMT timezone state data is kept here */
1363 : : static struct state *gmtptr = NULL;
1364 : :
2007 1365 [ + + ]: 159471 : if (gmtptr == NULL)
1366 : : {
1367 : : /* Allocate on first use */
1368 : 174 : gmtptr = (struct state *) malloc(sizeof(struct state));
1369 [ - + ]: 174 : if (gmtptr == NULL)
2007 tgl@sss.pgh.pa.us 1370 :UBC 0 : return NULL; /* errno should be set by malloc */
7268 tgl@sss.pgh.pa.us 1371 :CBC 174 : gmtload(gmtptr);
1372 : : }
1373 : :
5902 1374 : 159471 : result = timesub(timep, offset, gmtptr, tmp);
1375 : :
1376 : : /*
1377 : : * Could get fancy here and deliver something such as "+xx" or "-xx" if
1378 : : * offset is non-zero, but this is no time for a treasure hunt.
1379 : : */
7289 bruce@momjian.us 1380 [ - + ]: 159471 : if (offset != 0)
7268 tgl@sss.pgh.pa.us 1381 :UBC 0 : tmp->tm_zone = wildabbr;
1382 : : else
7268 tgl@sss.pgh.pa.us 1383 :CBC 159471 : tmp->tm_zone = gmtptr->chars;
1384 : :
5902 1385 : 159471 : return result;
1386 : : }
1387 : :
1388 : : struct pg_tm *
7255 1389 : 159471 : pg_gmtime(const pg_time_t *timep)
1390 : : {
2939 1391 : 159471 : return gmtsub(timep, 0, &tm);
1392 : : }
1393 : :
1394 : : /*
1395 : : * Return the number of leap years through the end of the given year
1396 : : * where, to make the math easy, the answer for year zero is defined as zero.
1397 : : */
1398 : :
1399 : : static int
2396 1400 : 4653138 : leaps_thru_end_of_nonneg(int y)
1401 : : {
1402 : 4653138 : return y / 4 - y / 100 + y / 400;
1403 : : }
1404 : :
1405 : : static int
5902 1406 : 4653138 : leaps_thru_end_of(const int y)
1407 : : {
1408 : : return (y < 0
2396 1409 : 1152 : ? -1 - leaps_thru_end_of_nonneg(-1 - y)
1410 [ + + ]: 4654290 : : leaps_thru_end_of_nonneg(y));
1411 : : }
1412 : :
1413 : : static struct pg_tm *
2939 1414 : 1119216 : timesub(const pg_time_t *timep, int32 offset,
1415 : : const struct state *sp, struct pg_tm *tmp)
1416 : : {
1417 : : const struct lsinfo *lp;
1418 : : pg_time_t tdays;
1419 : : int idays; /* unsigned would be so 2003 */
1420 : : int64 rem;
1421 : : int y;
1422 : : const int *ip;
1423 : : int64 corr;
1424 : : bool hit;
1425 : : int i;
1426 : :
7289 bruce@momjian.us 1427 : 1119216 : corr = 0;
2939 tgl@sss.pgh.pa.us 1428 : 1119216 : hit = false;
1429 [ + - ]: 1119216 : i = (sp == NULL) ? 0 : sp->leapcnt;
7268 bruce@momjian.us 1430 [ - + ]: 1119216 : while (--i >= 0)
1431 : : {
7289 bruce@momjian.us 1432 :UBC 0 : lp = &sp->lsis[i];
7268 1433 [ # # ]: 0 : if (*timep >= lp->ls_trans)
1434 : : {
7289 1435 : 0 : corr = lp->ls_corr;
2396 tgl@sss.pgh.pa.us 1436 : 0 : hit = (*timep == lp->ls_trans
1437 [ # # # # : 0 : && (i == 0 ? 0 : lp[-1].ls_corr) < corr);
# # ]
7289 bruce@momjian.us 1438 : 0 : break;
1439 : : }
1440 : : }
5902 tgl@sss.pgh.pa.us 1441 :CBC 1119216 : y = EPOCH_YEAR;
1442 : 1119216 : tdays = *timep / SECSPERDAY;
2939 1443 : 1119216 : rem = *timep % SECSPERDAY;
5902 1444 [ + + + + : 2326569 : while (tdays < 0 || tdays >= year_lengths[isleap(y)])
+ + + + +
+ ]
1445 : : {
1446 : : int newy;
1447 : : pg_time_t tdelta;
1448 : : int idelta;
1449 : : int leapdays;
1450 : :
1451 : 1207353 : tdelta = tdays / DAYSPERLYEAR;
1429 1452 [ + - - + ]: 1207353 : if (!((!TYPE_SIGNED(pg_time_t) || INT_MIN <= tdelta)
1453 : : && tdelta <= INT_MAX))
2939 tgl@sss.pgh.pa.us 1454 :UBC 0 : goto out_of_range;
5902 tgl@sss.pgh.pa.us 1455 :CBC 1207353 : idelta = tdelta;
1456 [ + + ]: 1207353 : if (idelta == 0)
1457 [ + + ]: 113621 : idelta = (tdays < 0) ? -1 : 1;
1458 : 1207353 : newy = y;
1459 [ - + ]: 1207353 : if (increment_overflow(&newy, idelta))
2939 tgl@sss.pgh.pa.us 1460 :UBC 0 : goto out_of_range;
5902 tgl@sss.pgh.pa.us 1461 :CBC 1207353 : leapdays = leaps_thru_end_of(newy - 1) -
1462 : 1207353 : leaps_thru_end_of(y - 1);
1463 : 1207353 : tdays -= ((pg_time_t) newy - y) * DAYSPERNYEAR;
1464 : 1207353 : tdays -= leapdays;
1465 : 1207353 : y = newy;
1466 : : }
1467 : :
1468 : : /*
1469 : : * Given the range, we can now fearlessly cast...
1470 : : */
1471 : 1119216 : idays = tdays;
1472 : 1119216 : rem += offset - corr;
7268 bruce@momjian.us 1473 [ + + ]: 1358760 : while (rem < 0)
1474 : : {
7289 1475 : 239544 : rem += SECSPERDAY;
5902 tgl@sss.pgh.pa.us 1476 : 239544 : --idays;
1477 : : }
7268 bruce@momjian.us 1478 [ + + ]: 1121587 : while (rem >= SECSPERDAY)
1479 : : {
7289 1480 : 2371 : rem -= SECSPERDAY;
5902 tgl@sss.pgh.pa.us 1481 : 2371 : ++idays;
1482 : : }
1483 [ + + ]: 1131201 : while (idays < 0)
1484 : : {
1485 [ - + ]: 11985 : if (increment_overflow(&y, -1))
2939 tgl@sss.pgh.pa.us 1486 :UBC 0 : goto out_of_range;
5902 tgl@sss.pgh.pa.us 1487 [ + + + + :CBC 11985 : idays += year_lengths[isleap(y)];
+ - ]
1488 : : }
1489 [ + + + + : 1119222 : while (idays >= year_lengths[isleap(y)])
+ + + + ]
1490 : : {
1491 [ + + - + : 6 : idays -= year_lengths[isleap(y)];
- - ]
1492 [ - + ]: 6 : if (increment_overflow(&y, 1))
2939 tgl@sss.pgh.pa.us 1493 :UBC 0 : goto out_of_range;
1494 : : }
5902 tgl@sss.pgh.pa.us 1495 :CBC 1119216 : tmp->tm_year = y;
1496 [ - + ]: 1119216 : if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
2939 tgl@sss.pgh.pa.us 1497 :UBC 0 : goto out_of_range;
5902 tgl@sss.pgh.pa.us 1498 :CBC 1119216 : tmp->tm_yday = idays;
1499 : :
1500 : : /*
1501 : : * The "extra" mods below avoid overflow problems.
1502 : : */
1503 : 1119216 : tmp->tm_wday = EPOCH_WDAY +
1504 : 1119216 : ((y - EPOCH_YEAR) % DAYSPERWEEK) *
1505 : 1119216 : (DAYSPERNYEAR % DAYSPERWEEK) +
1506 : 1119216 : leaps_thru_end_of(y - 1) -
1507 : 1119216 : leaps_thru_end_of(EPOCH_YEAR - 1) +
1508 : : idays;
1509 : 1119216 : tmp->tm_wday %= DAYSPERWEEK;
7289 bruce@momjian.us 1510 [ + + ]: 1119216 : if (tmp->tm_wday < 0)
1511 : 2070 : tmp->tm_wday += DAYSPERWEEK;
5902 tgl@sss.pgh.pa.us 1512 : 1119216 : tmp->tm_hour = (int) (rem / SECSPERHOUR);
1513 : 1119216 : rem %= SECSPERHOUR;
1514 : 1119216 : tmp->tm_min = (int) (rem / SECSPERMIN);
1515 : :
1516 : : /*
1517 : : * A positive leap second requires a special representation. This uses
1518 : : * "... ??:59:60" et seq.
1519 : : */
1520 : 1119216 : tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1521 [ + + + + : 1119216 : ip = mon_lengths[isleap(y)];
+ + ]
1522 [ + + ]: 4980628 : for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1523 : 3861412 : idays -= ip[tmp->tm_mon];
1524 : 1119216 : tmp->tm_mday = (int) (idays + 1);
7289 bruce@momjian.us 1525 : 1119216 : tmp->tm_isdst = 0;
7268 tgl@sss.pgh.pa.us 1526 : 1119216 : tmp->tm_gmtoff = offset;
5902 1527 : 1119216 : return tmp;
1528 : :
2939 tgl@sss.pgh.pa.us 1529 :UBC 0 : out_of_range:
1530 : 0 : errno = EOVERFLOW;
1531 : 0 : return NULL;
1532 : : }
1533 : :
1534 : : /*
1535 : : * Normalize logic courtesy Paul Eggert.
1536 : : */
1537 : :
1538 : : static bool
2939 tgl@sss.pgh.pa.us 1539 :CBC 2338560 : increment_overflow(int *ip, int j)
1540 : : {
1541 : 2338560 : int const i = *ip;
1542 : :
1543 : : /*----------
1544 : : * If i >= 0 there can only be overflow if i + j > INT_MAX
1545 : : * or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
1546 : : * If i < 0 there can only be overflow if i + j < INT_MIN
1547 : : * or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
1548 : : *----------
1549 : : */
1550 [ + + - + ]: 2338560 : if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
2939 tgl@sss.pgh.pa.us 1551 :UBC 0 : return true;
2939 tgl@sss.pgh.pa.us 1552 :CBC 2338560 : *ip += j;
1553 : 2338560 : return false;
1554 : : }
1555 : :
1556 : : static bool
1557 : 18572800 : increment_overflow_time(pg_time_t *tp, int32 j)
1558 : : {
1559 : : /*----------
1560 : : * This is like
1561 : : * 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...',
1562 : : * except that it does the right thing even if *tp + j would overflow.
1563 : : *----------
1564 : : */
1565 [ + + - + ]: 37145600 : if (!(j < 0
2396 1566 : 1160800 : ? (TYPE_SIGNED(pg_time_t) ? TIME_T_MIN - j <= *tp : -1 - j < *tp)
1567 : 17412000 : : *tp <= TIME_T_MAX - j))
2939 tgl@sss.pgh.pa.us 1568 :UBC 0 : return true;
2939 tgl@sss.pgh.pa.us 1569 :CBC 18572800 : *tp += j;
1570 : 18572800 : return false;
1571 : : }
1572 : :
1573 : : static int64
1397 1574 : 11607801 : leapcorr(struct state const *sp, pg_time_t t)
1575 : : {
1576 : : struct lsinfo const *lp;
1577 : : int i;
1578 : :
1579 : 11607801 : i = sp->leapcnt;
1580 [ - + ]: 11607801 : while (--i >= 0)
1581 : : {
1397 tgl@sss.pgh.pa.us 1582 :UBC 0 : lp = &sp->lsis[i];
1583 [ # # ]: 0 : if (t >= lp->ls_trans)
1584 : 0 : return lp->ls_corr;
1585 : : }
1397 tgl@sss.pgh.pa.us 1586 :CBC 11607801 : return 0;
1587 : : }
1588 : :
1589 : : /*
1590 : : * Find the next DST transition time in the given zone after the given time
1591 : : *
1592 : : * *timep and *tz are input arguments, the other parameters are output values.
1593 : : *
1594 : : * When the function result is 1, *boundary is set to the pg_time_t
1595 : : * representation of the next DST transition time after *timep,
1596 : : * *before_gmtoff and *before_isdst are set to the GMT offset and isdst
1597 : : * state prevailing just before that boundary (in particular, the state
1598 : : * prevailing at *timep), and *after_gmtoff and *after_isdst are set to
1599 : : * the state prevailing just after that boundary.
1600 : : *
1601 : : * When the function result is 0, there is no known DST transition
1602 : : * after *timep, but *before_gmtoff and *before_isdst indicate the GMT
1603 : : * offset and isdst state prevailing at *timep. (This would occur in
1604 : : * DST-less time zones, or if a zone has permanently ceased using DST.)
1605 : : *
1606 : : * A function result of -1 indicates failure (this case does not actually
1607 : : * occur in our current implementation).
1608 : : */
1609 : : int
7104 1610 : 28055 : pg_next_dst_boundary(const pg_time_t *timep,
1611 : : long int *before_gmtoff,
1612 : : int *before_isdst,
1613 : : pg_time_t *boundary,
1614 : : long int *after_gmtoff,
1615 : : int *after_isdst,
1616 : : const pg_tz *tz)
1617 : : {
1618 : : const struct state *sp;
1619 : : const struct ttinfo *ttisp;
1620 : : int i;
1621 : : int j;
1622 : 28055 : const pg_time_t t = *timep;
1623 : :
6935 bruce@momjian.us 1624 : 28055 : sp = &tz->state;
7104 tgl@sss.pgh.pa.us 1625 [ + + ]: 28055 : if (sp->timecnt == 0)
1626 : : {
1627 : : /* non-DST zone, use lowest-numbered standard type */
1628 : 1169 : i = 0;
1629 [ - + ]: 1169 : while (sp->ttis[i].tt_isdst)
7104 tgl@sss.pgh.pa.us 1630 [ # # ]:UBC 0 : if (++i >= sp->typecnt)
1631 : : {
1632 : 0 : i = 0;
1633 : 0 : break;
1634 : : }
7104 tgl@sss.pgh.pa.us 1635 :CBC 1169 : ttisp = &sp->ttis[i];
1733 1636 : 1169 : *before_gmtoff = ttisp->tt_utoff;
7104 1637 : 1169 : *before_isdst = ttisp->tt_isdst;
1638 : 1169 : return 0;
1639 : : }
5902 1640 [ + + + - ]: 26886 : if ((sp->goback && t < sp->ats[0]) ||
1641 [ + + + + ]: 26886 : (sp->goahead && t > sp->ats[sp->timecnt - 1]))
1642 : : {
1643 : : /* For values outside the transition table, extrapolate */
1644 : 90 : pg_time_t newt = t;
1645 : : pg_time_t seconds;
1646 : : pg_time_t tcycles;
1647 : : int64 icycles;
1648 : : int result;
1649 : :
1650 [ - + ]: 90 : if (t < sp->ats[0])
5902 tgl@sss.pgh.pa.us 1651 :UBC 0 : seconds = sp->ats[0] - t;
1652 : : else
5421 bruce@momjian.us 1653 :CBC 90 : seconds = t - sp->ats[sp->timecnt - 1];
5902 tgl@sss.pgh.pa.us 1654 : 90 : --seconds;
1655 : 90 : tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1656 : 90 : ++tcycles;
1657 : 90 : icycles = tcycles;
1658 [ + - - + ]: 90 : if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
5902 tgl@sss.pgh.pa.us 1659 :UBC 0 : return -1;
5902 tgl@sss.pgh.pa.us 1660 :CBC 90 : seconds = icycles;
1661 : 90 : seconds *= YEARSPERREPEAT;
1662 : 90 : seconds *= AVGSECSPERYEAR;
1663 [ - + ]: 90 : if (t < sp->ats[0])
5902 tgl@sss.pgh.pa.us 1664 :UBC 0 : newt += seconds;
1665 : : else
5421 bruce@momjian.us 1666 :CBC 90 : newt -= seconds;
5902 tgl@sss.pgh.pa.us 1667 [ + - ]: 90 : if (newt < sp->ats[0] ||
1668 [ - + ]: 90 : newt > sp->ats[sp->timecnt - 1])
5421 bruce@momjian.us 1669 :UBC 0 : return -1; /* "cannot happen" */
1670 : :
5902 tgl@sss.pgh.pa.us 1671 :CBC 90 : result = pg_next_dst_boundary(&newt, before_gmtoff,
1672 : : before_isdst,
1673 : : boundary,
1674 : : after_gmtoff,
1675 : : after_isdst,
1676 : : tz);
1677 [ - + ]: 90 : if (t < sp->ats[0])
5902 tgl@sss.pgh.pa.us 1678 :UBC 0 : *boundary -= seconds;
1679 : : else
5902 tgl@sss.pgh.pa.us 1680 :CBC 90 : *boundary += seconds;
1681 : 90 : return result;
1682 : : }
1683 : :
4372 1684 [ + + ]: 26796 : if (t >= sp->ats[sp->timecnt - 1])
1685 : : {
1686 : : /* No known transition > t, so use last known segment's type */
7104 1687 : 396 : i = sp->types[sp->timecnt - 1];
1688 : 396 : ttisp = &sp->ttis[i];
1733 1689 : 396 : *before_gmtoff = ttisp->tt_utoff;
7104 1690 : 396 : *before_isdst = ttisp->tt_isdst;
1691 : 396 : return 0;
1692 : : }
4372 1693 [ + + ]: 26400 : if (t < sp->ats[0])
1694 : : {
1695 : : /* For "before", use lowest-numbered standard type */
7104 1696 : 312 : i = 0;
1697 [ - + ]: 312 : while (sp->ttis[i].tt_isdst)
7104 tgl@sss.pgh.pa.us 1698 [ # # ]:UBC 0 : if (++i >= sp->typecnt)
1699 : : {
1700 : 0 : i = 0;
1701 : 0 : break;
1702 : : }
7104 tgl@sss.pgh.pa.us 1703 :CBC 312 : ttisp = &sp->ttis[i];
1733 1704 : 312 : *before_gmtoff = ttisp->tt_utoff;
7104 1705 : 312 : *before_isdst = ttisp->tt_isdst;
1706 : 312 : *boundary = sp->ats[0];
1707 : : /* And for "after", use the first segment's type */
1708 : 312 : i = sp->types[0];
1709 : 312 : ttisp = &sp->ttis[i];
1733 1710 : 312 : *after_gmtoff = ttisp->tt_utoff;
7104 1711 : 312 : *after_isdst = ttisp->tt_isdst;
1712 : 312 : return 1;
1713 : : }
1714 : : /* Else search to find the boundary following t */
1715 : : {
5421 bruce@momjian.us 1716 : 26088 : int lo = 1;
4372 tgl@sss.pgh.pa.us 1717 : 26088 : int hi = sp->timecnt - 1;
1718 : :
5902 1719 [ + + ]: 298912 : while (lo < hi)
1720 : : {
5421 bruce@momjian.us 1721 : 272824 : int mid = (lo + hi) >> 1;
1722 : :
5902 tgl@sss.pgh.pa.us 1723 [ + + ]: 272824 : if (t < sp->ats[mid])
1724 : 197525 : hi = mid;
1725 : : else
5421 bruce@momjian.us 1726 : 75299 : lo = mid + 1;
1727 : : }
5902 tgl@sss.pgh.pa.us 1728 : 26088 : i = lo;
1729 : : }
7104 1730 : 26088 : j = sp->types[i - 1];
1731 : 26088 : ttisp = &sp->ttis[j];
1733 1732 : 26088 : *before_gmtoff = ttisp->tt_utoff;
7104 1733 : 26088 : *before_isdst = ttisp->tt_isdst;
1734 : 26088 : *boundary = sp->ats[i];
1735 : 26088 : j = sp->types[i];
1736 : 26088 : ttisp = &sp->ttis[j];
1733 1737 : 26088 : *after_gmtoff = ttisp->tt_utoff;
7104 1738 : 26088 : *after_isdst = ttisp->tt_isdst;
1739 : 26088 : return 1;
1740 : : }
1741 : :
1742 : : /*
1743 : : * Identify a timezone abbreviation's meaning in the given zone
1744 : : *
1745 : : * Determine the GMT offset and DST flag associated with the abbreviation.
1746 : : * This is generally used only when the abbreviation has actually changed
1747 : : * meaning over time; therefore, we also take a UTC cutoff time, and return
1748 : : * the meaning in use at or most recently before that time, or the meaning
1749 : : * in first use after that time if the abbrev was never used before that.
1750 : : *
1751 : : * On success, returns true and sets *gmtoff and *isdst. If the abbreviation
1752 : : * was never used at all in this zone, returns false.
1753 : : *
1754 : : * Note: abbrev is matched case-sensitively; it should be all-upper-case.
1755 : : */
1756 : : bool
3468 1757 : 576 : pg_interpret_timezone_abbrev(const char *abbrev,
1758 : : const pg_time_t *timep,
1759 : : long int *gmtoff,
1760 : : int *isdst,
1761 : : const pg_tz *tz)
1762 : : {
1763 : : const struct state *sp;
1764 : : const char *abbrs;
1765 : : const struct ttinfo *ttisp;
1766 : : int abbrind;
1767 : : int cutoff;
1768 : : int i;
1769 : 576 : const pg_time_t t = *timep;
1770 : :
1771 : 576 : sp = &tz->state;
1772 : :
1773 : : /*
1774 : : * Locate the abbreviation in the zone's abbreviation list. We assume
1775 : : * there are not duplicates in the list.
1776 : : */
1777 : 576 : abbrs = sp->chars;
1778 : 576 : abbrind = 0;
1779 [ + + ]: 3168 : while (abbrind < sp->charcnt)
1780 : : {
1781 [ + + ]: 2730 : if (strcmp(abbrev, abbrs + abbrind) == 0)
1782 : 138 : break;
1783 [ + + ]: 10749 : while (abbrs[abbrind] != '\0')
1784 : 8157 : abbrind++;
1785 : 2592 : abbrind++;
1786 : : }
1787 [ + + ]: 576 : if (abbrind >= sp->charcnt)
2939 1788 : 438 : return false; /* not there! */
1789 : :
1790 : : /*
1791 : : * Unlike pg_next_dst_boundary, we needn't sweat about extrapolation
1792 : : * (goback/goahead zones). Finding the newest or oldest meaning of the
1793 : : * abbreviation should get us what we want, since extrapolation would just
1794 : : * be repeating the newest or oldest meanings.
1795 : : *
1796 : : * Use binary search to locate the first transition > cutoff time.
1797 : : */
1798 : : {
3468 1799 : 138 : int lo = 0;
1800 : 138 : int hi = sp->timecnt;
1801 : :
1802 [ + + ]: 966 : while (lo < hi)
1803 : : {
1804 : 828 : int mid = (lo + hi) >> 1;
1805 : :
1806 [ + + ]: 828 : if (t < sp->ats[mid])
1807 : 99 : hi = mid;
1808 : : else
1809 : 729 : lo = mid + 1;
1810 : : }
1811 : 138 : cutoff = lo;
1812 : : }
1813 : :
1814 : : /*
1815 : : * Scan backwards to find the latest interval using the given abbrev
1816 : : * before the cutoff time.
1817 : : */
1818 [ + - ]: 138 : for (i = cutoff - 1; i >= 0; i--)
1819 : : {
1820 : 138 : ttisp = &sp->ttis[sp->types[i]];
1733 1821 [ + - ]: 138 : if (ttisp->tt_desigidx == abbrind)
1822 : : {
1823 : 138 : *gmtoff = ttisp->tt_utoff;
3468 1824 : 138 : *isdst = ttisp->tt_isdst;
2939 1825 : 138 : return true;
1826 : : }
1827 : : }
1828 : :
1829 : : /*
1830 : : * Not there, so scan forwards to find the first one after.
1831 : : */
3468 tgl@sss.pgh.pa.us 1832 [ # # ]:UBC 0 : for (i = cutoff; i < sp->timecnt; i++)
1833 : : {
1834 : 0 : ttisp = &sp->ttis[sp->types[i]];
1733 1835 [ # # ]: 0 : if (ttisp->tt_desigidx == abbrind)
1836 : : {
1837 : 0 : *gmtoff = ttisp->tt_utoff;
3468 1838 : 0 : *isdst = ttisp->tt_isdst;
2939 1839 : 0 : return true;
1840 : : }
1841 : : }
1842 : :
1843 : 0 : return false; /* hm, not actually used in any interval? */
1844 : : }
1845 : :
1846 : : /*
1847 : : * If the given timezone uses only one GMT offset, store that offset
1848 : : * into *gmtoff and return true, else return false.
1849 : : */
1850 : : bool
6388 tgl@sss.pgh.pa.us 1851 :CBC 605 : pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff)
1852 : : {
1853 : : /*
1854 : : * The zone could have more than one ttinfo, if it's historically used
1855 : : * more than one abbreviation. We return true as long as they all have
1856 : : * the same gmtoff.
1857 : : */
1858 : : const struct state *sp;
1859 : : int i;
1860 : :
1861 : 605 : sp = &tz->state;
1862 [ + + ]: 622 : for (i = 1; i < sp->typecnt; i++)
1863 : : {
1733 1864 [ + + ]: 59 : if (sp->ttis[i].tt_utoff != sp->ttis[0].tt_utoff)
6388 1865 : 42 : return false;
1866 : : }
1733 1867 : 563 : *gmtoff = sp->ttis[0].tt_utoff;
6388 1868 : 563 : return true;
1869 : : }
1870 : :
1871 : : /*
1872 : : * Return the name of the current timezone
1873 : : */
1874 : : const char *
6935 bruce@momjian.us 1875 : 31222 : pg_get_timezone_name(pg_tz *tz)
1876 : : {
1877 [ + - ]: 31222 : if (tz)
1878 : 31222 : return tz->TZname;
7268 tgl@sss.pgh.pa.us 1879 :UBC 0 : return NULL;
1880 : : }
1881 : :
1882 : : /*
1883 : : * Check whether timezone is acceptable.
1884 : : *
1885 : : * What we are doing here is checking for leap-second-aware timekeeping.
1886 : : * We need to reject such TZ settings because they'll wreak havoc with our
1887 : : * date/time arithmetic.
1888 : : */
1889 : : bool
4601 tgl@sss.pgh.pa.us 1890 :CBC 17361 : pg_tz_acceptable(pg_tz *tz)
1891 : : {
1892 : : struct pg_tm *tt;
1893 : : pg_time_t time2000;
1894 : :
1895 : : /*
1896 : : * To detect leap-second timekeeping, run pg_localtime for what should be
1897 : : * GMT midnight, 2000-01-01. Insist that the tm_sec value be zero; any
1898 : : * other result has to be due to leap seconds.
1899 : : */
1900 : 17361 : time2000 = (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
1901 : 17361 : tt = pg_localtime(&time2000, tz);
1902 [ + - - + ]: 17361 : if (!tt || tt->tm_sec != 0)
4601 tgl@sss.pgh.pa.us 1903 :UBC 0 : return false;
1904 : :
4601 tgl@sss.pgh.pa.us 1905 :CBC 17361 : return true;
1906 : : }
|