aboutsummaryrefslogtreecommitdiff
path: root/src/timezone/zic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/timezone/zic.c')
-rw-r--r--src/timezone/zic.c74
1 files changed, 39 insertions, 35 deletions
diff --git a/src/timezone/zic.c b/src/timezone/zic.c
index ae61264364c..4613919afe4 100644
--- a/src/timezone/zic.c
+++ b/src/timezone/zic.c
@@ -167,9 +167,11 @@ PERCENT_Z_LEN_BOUND = sizeof "+995959" - 1};
QTBUG-53071 <https://bugreports.qt.io/browse/QTBUG-53071>. This
workaround will no longer be needed when Qt 5.6.1 and earlier are
obsolete, say in the year 2021. */
+#ifndef WORK_AROUND_QTBUG_53071
enum
{
WORK_AROUND_QTBUG_53071 = true};
+#endif
static int charcnt;
static bool errors;
@@ -1912,12 +1914,6 @@ atcomp(const void *avp, const void *bvp)
return (a < b) ? -1 : (a > b);
}
-static bool
-is32(const zic_t x)
-{
- return x == ((zic_t) ((int32) x));
-}
-
static void
swaptypes(int i, int j)
{
@@ -1971,7 +1967,12 @@ writezone(const char *const name, const char *const string, char version,
zic_t one = 1;
zic_t y2038_boundary = one << 31;
ptrdiff_t nats = timecnt + WORK_AROUND_QTBUG_53071;
- zic_t *ats = emalloc(size_product(nats, sizeof *ats + 1));
+
+ /*
+ * Allocate the ATS and TYPES arrays via a single malloc, as this is a bit
+ * faster.
+ */
+ zic_t *ats = emalloc(MAXALIGN(size_product(nats, sizeof *ats + 1)));
void *typesptr = ats + nats;
unsigned char *types = typesptr;
@@ -2030,20 +2031,6 @@ writezone(const char *const name, const char *const string, char version,
}
/*
- * Work around QTBUG-53071 for timestamps less than y2038_boundary - 1, by
- * inserting a no-op transition at time y2038_boundary - 1. This works
- * only for timestamps before the boundary, which should be good enough in
- * practice as QTBUG-53071 should be long-dead by 2038.
- */
- if (WORK_AROUND_QTBUG_53071 && timecnt != 0
- && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<'))
- {
- ats[timecnt] = y2038_boundary - 1;
- types[timecnt] = types[timecnt - 1];
- timecnt++;
- }
-
- /*
* Correct for leap seconds.
*/
for (i = 0; i < timecnt; ++i)
@@ -2058,31 +2045,47 @@ writezone(const char *const name, const char *const string, char version,
}
/*
+ * Work around QTBUG-53071 for timestamps less than y2038_boundary - 1, by
+ * inserting a no-op transition at time y2038_boundary - 1. This works
+ * only for timestamps before the boundary, which should be good enough in
+ * practice as QTBUG-53071 should be long-dead by 2038. Do this after
+ * correcting for leap seconds, as the idea is to insert a transition just
+ * before 32-bit pg_time_t rolls around, and this occurs at a slightly
+ * different moment if transitions are leap-second corrected.
+ */
+ if (WORK_AROUND_QTBUG_53071 && timecnt != 0
+ && ats[timecnt - 1] < y2038_boundary - 1 && strchr(string, '<'))
+ {
+ ats[timecnt] = y2038_boundary - 1;
+ types[timecnt] = types[timecnt - 1];
+ timecnt++;
+ }
+
+ /*
* Figure out 32-bit-limited starts and counts.
*/
timecnt32 = timecnt;
timei32 = 0;
leapcnt32 = leapcnt;
leapi32 = 0;
- while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
+ while (0 < timecnt32 && PG_INT32_MAX < ats[timecnt32 - 1])
--timecnt32;
- while (timecnt32 > 0 && !is32(ats[timei32]))
+ while (1 < timecnt32 && ats[timei32] < PG_INT32_MIN
+ && ats[timei32 + 1] <= PG_INT32_MIN)
{
+ /*
+ * Discard too-low transitions, except keep any last too-low
+ * transition if no transition is exactly at PG_INT32_MIN. The kept
+ * transition will be output as an PG_INT32_MIN "transition"
+ * appropriate for buggy 32-bit clients that do not use time type 0
+ * for timestamps before the first transition; see below.
+ */
--timecnt32;
++timei32;
}
-
- /*
- * Output an INT32_MIN "transition" if appropriate; see below.
- */
- if (timei32 > 0 && ats[timei32] > PG_INT32_MIN)
- {
- --timei32;
- ++timecnt32;
- }
- while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
+ while (0 < leapcnt32 && PG_INT32_MAX < trans[leapcnt32 - 1])
--leapcnt32;
- while (leapcnt32 > 0 && !is32(trans[leapi32]))
+ while (0 < leapcnt32 && trans[leapi32] < PG_INT32_MIN)
{
--leapcnt32;
++leapi32;
@@ -2315,7 +2318,8 @@ writezone(const char *const name, const char *const string, char version,
if (pass == 1)
/*
- * Output an INT32_MIN "transition" if appropriate; see above.
+ * Output an PG_INT32_MIN "transition" if appropriate; see
+ * above.
*/
puttzcode(((ats[i] < PG_INT32_MIN) ?
PG_INT32_MIN : ats[i]), fp);