/* * See how well a specific timezone setting matches the system behavior * * We score a timezone setting according to the number of test times it * matches. (The test times are ordered later-to-earlier, but this routine * doesn't actually know that; it just scans until the first non-match.) * * We return -1 for a completely unusable setting; this is worse than the * score of zero for a setting that works but matches not even the first * test time. */ static int score_timezone(const char *tzname, struct tztry * tt) { int i; pg_time_t pgtt; struct tm* systm; struct pg_tm* pgtm; char cbuf[TZ_STRLEN_MAX + 1]; pg_tz tz; /* * Load timezone directly. Don't use pg_tzset, because we don't want all * timezones loaded in the cache at startup. */ if (tzload(tzname, NULL, &tz.state, TRUE) != 0) { if (tzname[0] == ':' || tzparse(tzname, &tz.state, FALSE) != 0) { return -1; /* can't handle the TZ name at all */ } } /* Reject if leap seconds involved */ if (!tz_acceptable(&tz)) { elog(DEBUG4, "Reject TZ \"%s\": uses leap seconds", tzname); return -1; } /* Check for match at all the test times */ for (i = 0; i < tt->n_test_times; i++) { pgtt = (pg_time_t) (tt->test_times[i]); pgtm = pg_localtime(&pgtt, &tz); if (!pgtm) return -1; /* probably shouldn't happen */ systm = localtime(&(tt->test_times[i])); if (!systm) { elog(DEBUG4, "TZ \"%s\" scores %d:" " at %ld %04d-%02d-%02d %02d:%02d:%02d %s, system had no data", tzname, i, (long) pgtt, pgtm->tm_year + 1900, pgtm->tm_mon + 1, pgtm->tm_mday, pgtm->tm_hour, pgtm->tm_min, pgtm->tm_sec, pgtm->tm_isdst ? "dst" : "std"); return i; } if (!compare_tm(systm, pgtm)) { elog(DEBUG4, "TZ \"%s\" scores %d:" " at %ld %04d-%02d-%02d %02d:%02d:%02d %s" " versus %04d-%02d-%02d %02d:%02d:%02d %s", tzname, i, (long) pgtt, pgtm->tm_year + 1900, pgtm->tm_mon + 1, pgtm->tm_mday, pgtm->tm_hour, pgtm->tm_min, pgtm->tm_sec, pgtm->tm_isdst ? "dst" : "std", systm->tm_year + 1900, systm->tm_mon + 1, systm->tm_mday, systm->tm_hour, systm->tm_min, systm->tm_sec, systm->tm_isdst ? "dst" : "std"); return i; } if (systm->tm_isdst >= 0) { /* Check match of zone names, too */ if (pgtm->tm_zone == NULL) return -1; /* probably shouldn't happen */ memset(cbuf, 0, sizeof(cbuf)); strftime(cbuf, sizeof(cbuf) - 1, "%Z", systm); /* zone abbr */ if (strcmp(cbuf, pgtm->tm_zone) != 0) { elog(DEBUG4, "TZ \"%s\" scores %d: at %ld \"%s\" versus \"%s\"", tzname, i, (long) pgtt, pgtm->tm_zone, cbuf); return i; } } } elog(DEBUG4, "TZ \"%s\" gets max score %d", tzname, i); return i; }
/* * See how well a specific timezone setting matches the system behavior * * We score a timezone setting according to the number of test times it * matches. (The test times are ordered later-to-earlier, but this routine * doesn't actually know that; it just scans until the first non-match.) * * We return -1 for a completely unusable setting; this is worse than the * score of zero for a setting that works but matches not even the first * test time. */ static int score_timezone(const char *tzname, struct tztry *tt) { int i; pg_time_t pgtt; struct tm *systm; struct pg_tm *pgtm; char cbuf[TZ_STRLEN_MAX + 1]; pg_tz *tz; /* Load timezone definition */ tz = pg_load_tz(tzname); if (!tz) return -1; /* unrecognized zone name */ /* Reject if leap seconds involved */ if (!pg_tz_acceptable(tz)) { #ifdef DEBUG_IDENTIFY_TIMEZONE fprintf(stderr, "Reject TZ \"%s\": uses leap seconds\n", tzname); #endif return -1; } /* Check for match at all the test times */ for (i = 0; i < tt->n_test_times; i++) { pgtt = (pg_time_t) (tt->test_times[i]); pgtm = pg_localtime(&pgtt, tz); if (!pgtm) return -1; /* probably shouldn't happen */ systm = localtime(&(tt->test_times[i])); if (!systm) { #ifdef DEBUG_IDENTIFY_TIMEZONE fprintf(stderr, "TZ \"%s\" scores %d: at %ld %04d-%02d-%02d %02d:%02d:%02d %s, system had no data\n", tzname, i, (long) pgtt, pgtm->tm_year + 1900, pgtm->tm_mon + 1, pgtm->tm_mday, pgtm->tm_hour, pgtm->tm_min, pgtm->tm_sec, pgtm->tm_isdst ? "dst" : "std"); #endif return i; } if (!compare_tm(systm, pgtm)) { #ifdef DEBUG_IDENTIFY_TIMEZONE fprintf(stderr, "TZ \"%s\" scores %d: at %ld %04d-%02d-%02d %02d:%02d:%02d %s versus %04d-%02d-%02d %02d:%02d:%02d %s\n", tzname, i, (long) pgtt, pgtm->tm_year + 1900, pgtm->tm_mon + 1, pgtm->tm_mday, pgtm->tm_hour, pgtm->tm_min, pgtm->tm_sec, pgtm->tm_isdst ? "dst" : "std", systm->tm_year + 1900, systm->tm_mon + 1, systm->tm_mday, systm->tm_hour, systm->tm_min, systm->tm_sec, systm->tm_isdst ? "dst" : "std"); #endif return i; } if (systm->tm_isdst >= 0) { /* Check match of zone names, too */ if (pgtm->tm_zone == NULL) return -1; /* probably shouldn't happen */ memset(cbuf, 0, sizeof(cbuf)); strftime(cbuf, sizeof(cbuf) - 1, "%Z", systm); /* zone abbr */ if (strcmp(cbuf, pgtm->tm_zone) != 0) { #ifdef DEBUG_IDENTIFY_TIMEZONE fprintf(stderr, "TZ \"%s\" scores %d: at %ld \"%s\" versus \"%s\"\n", tzname, i, (long) pgtt, pgtm->tm_zone, cbuf); #endif return i; } } } #ifdef DEBUG_IDENTIFY_TIMEZONE fprintf(stderr, "TZ \"%s\" gets max score %d\n", tzname, i); #endif return i; }