static int read_config_from_json(json_t *root) { int ret; ret = read_cfg_bool(root, "debug", &settings.debug, false, false); if (ret < 0) { printf("read debug config fail: %d\n", ret); return -__LINE__; } ret = load_cfg_process(root, "process", &settings.process); if (ret < 0) { printf("load process config fail: %d\n", ret); return -__LINE__; } ret = load_cfg_log(root, "log", &settings.log); if (ret < 0) { printf("load log config fail: %d\n", ret); return -__LINE__; } ret = load_cfg_alert(root, "alert", &settings.alert); if (ret < 0) { printf("load alert config fail: %d\n", ret); return -__LINE__; } ret = load_cfg_rpc_svr(root, "svr", &settings.svr); if (ret < 0) { printf("load svr config fail: %d\n", ret); return -__LINE__; } ret = load_cfg_kafka_consumer(root, "deals", &settings.deals); if (ret < 0) { printf("load kafka deals config fail: %d\n", ret); return -__LINE__; } ret = load_cfg_redis_sentinel(root, "redis", &settings.redis); if (ret < 0) { printf("load kafka deals config fail: %d\n", ret); return -__LINE__; } ERR_RET_LN(read_cfg_int(root, "sec_max", &settings.sec_max, false, 86400 * 7)); ERR_RET_LN(read_cfg_int(root, "min_max", &settings.min_max, false, 60 * 24 * 365)); ERR_RET_LN(read_cfg_int(root, "hour_max", &settings.hour_max, false, 24 * 365 * 10)); ERR_RET_LN(read_cfg_real(root, "cache_timeout", &settings.cache_timeout, false, 0.45)); settings.timezone = get_timezone_offset(); return 0; }
/* * Try to identify a timezone name (in our terminology) that best matches the * observed behavior of the system timezone library. We cannot assume that * the system TZ environment setting (if indeed there is one) matches our * terminology, so we ignore it and just look at what localtime() returns. */ static const char* identify_system_timezone(void) { static char resultbuf[TZ_STRLEN_MAX + 1]; time_t tnow; time_t t; struct tztry tt; struct tm *tm; int thisyear; int bestscore; char tmptzdir[MAX_PG_PATH]; int std_ofs; char std_zone_name[TZ_STRLEN_MAX + 1]; char dst_zone_name[TZ_STRLEN_MAX + 1]; char cbuf[TZ_STRLEN_MAX + 1]; /* Initialize OS timezone library */ tzset(); /* * Set up the list of dates to be probed to see how well our timezone * matches the system zone. We first probe January and July of the * current year; this serves to quickly eliminate the vast majority of the * TZ database entries. If those dates match, we probe every week for 100 * years backwards from the current July. (Weekly resolution is good * enough to identify DST transition rules, since everybody switches on * Sundays.) This is sufficient to cover most of the Unix time_t range, * and we don't want to look further than that since many systems won't * have sane TZ behavior further back anyway. The further back the zone * matches, the better we score it. This may seem like a rather random * way of doing things, but experience has shown that system-supplied * timezone definitions are likely to have DST behavior that is right for * the recent past and not so accurate further back. Scoring in this way * allows us to recognize zones that have some commonality with the zic * database, without insisting on exact match. (Note: we probe Thursdays, * not Sundays, to avoid triggering DST-transition bugs in localtime * itself.) */ tnow = time(NULL); tm = localtime(&tnow); if (!tm) return NULL; /* give up if localtime is broken... */ thisyear = tm->tm_year + 1900; t = build_time_t(thisyear, 1, 15); /* * Round back to GMT midnight Thursday. This depends on the knowledge * that the time_t origin is Thu Jan 01 1970. (With a different origin * we'd be probing some other day of the week, but it wouldn't matter * anyway unless localtime() had DST-transition bugs.) */ t -= (t % T_WEEK); tt.n_test_times = 0; tt.test_times[tt.n_test_times++] = t; t = build_time_t(thisyear, 7, 15); t -= (t % T_WEEK); tt.test_times[tt.n_test_times++] = t; while (tt.n_test_times < MAX_TEST_TIMES) { t -= T_WEEK; tt.test_times[tt.n_test_times++] = t; } /* Search for the best-matching timezone file */ strcpy(tmptzdir, pg_TZDIR()); bestscore = -1; resultbuf[0] = '\0'; scan_available_timezones(tmptzdir, tmptzdir + strlen(tmptzdir) + 1, &tt, &bestscore, resultbuf); if (bestscore > 0) { /* Ignore zic's rather silly "Factory" time zone; use GMT instead */ if (strcmp(resultbuf, "Factory") == 0) return NULL; return resultbuf; } /* * Couldn't find a match in the database, so next we try constructed zone * names (like "PST8PDT"). * * First we need to determine the names of the local standard and daylight * zones. The idea here is to scan forward from today until we have seen * both zones, if both are in use. */ memset(std_zone_name, 0, sizeof(std_zone_name)); memset(dst_zone_name, 0, sizeof(dst_zone_name)); std_ofs = 0; tnow = time(NULL); /* * Round back to a GMT midnight so results don't depend on local time of * day */ tnow -= (tnow % T_DAY); /* * We have to look a little further ahead than one year, in case today is * just past a DST boundary that falls earlier in the year than the next * similar boundary. Arbitrarily scan up to 14 months. */ for (t = tnow; t <= tnow + T_MONTH * 14; t += T_MONTH) { tm = localtime(&t); if (!tm) continue; if (tm->tm_isdst < 0) continue; if (tm->tm_isdst == 0 && std_zone_name[0] == '\0') { /* found STD zone */ memset(cbuf, 0, sizeof(cbuf)); strftime(cbuf, sizeof(cbuf) - 1, "%Z", tm); /* zone abbr */ strcpy(std_zone_name, cbuf); std_ofs = get_timezone_offset(tm); } if (tm->tm_isdst > 0 && dst_zone_name[0] == '\0') { /* found DST zone */ memset(cbuf, 0, sizeof(cbuf)); strftime(cbuf, sizeof(cbuf) - 1, "%Z", tm); /* zone abbr */ strcpy(dst_zone_name, cbuf); } /* Done if found both */ if (std_zone_name[0] && dst_zone_name[0]) break; } /* We should have found a STD zone name by now... */ if (std_zone_name[0] == '\0') { ereport(LOG, ( errmsg("could not determine system time zone"), errdetail("The PostgreSQL time zone will be set to \"%s\".", "GMT"), errhint("You can specify the correct timezone in postgresql.conf."))); return NULL; /* go to GMT */ } /* If we found DST then try STD<ofs>DST */ if (dst_zone_name[0] != '\0') { snprintf(resultbuf, sizeof(resultbuf), "%s%d%s", std_zone_name, -std_ofs / 3600, dst_zone_name); if (score_timezone(resultbuf, &tt) > 0) return resultbuf; } /* Try just the STD timezone (works for GMT at least) */ strcpy(resultbuf, std_zone_name); if (score_timezone(resultbuf, &tt) > 0) return resultbuf; /* Try STD<ofs> */ snprintf(resultbuf, sizeof(resultbuf), "%s%d", std_zone_name, -std_ofs / 3600); if (score_timezone(resultbuf, &tt) > 0) return resultbuf; /* * Did not find the timezone. Fallback to use a GMT zone. Note that the * zic timezone database names the GMT-offset zones in POSIX style: plus * is west of Greenwich. It's unfortunate that this is opposite of SQL * conventions. Should we therefore change the names? Probably not... */ snprintf(resultbuf, sizeof(resultbuf), "Etc/GMT%s%d", (-std_ofs > 0) ? "+" : "", -std_ofs / 3600); ereport(LOG, ( errmsg("could not recognize system time zone"), errdetail("The PostgreSQL time zone will be set to \"%s\".", resultbuf), errhint("You can specify the correct timezone in postgresql.conf."))); return resultbuf; }