time_zone: Remove string ops for determing zone

MinGW's strftime implementation does not work and cannot be used to
determine the time zone. Besides that, the string operations are
actually unnecessary since we can get the offset from
std::localtime.

Compare localtime to gmtime to find the zone offset on all platforms.
This commit is contained in:
lat9nq 2023-07-10 17:51:34 -04:00
parent e32ce6cc69
commit 90d76333da

View file

@ -33,32 +33,27 @@ std::string GetDefaultTimeZone() {
return "GMT"; return "GMT";
} }
static std::string GetOsTimeZoneOffset() { // Results are not comparable to seconds since Epoch
const std::time_t t{std::time(nullptr)}; static std::time_t TmSpecToSeconds(const struct std::tm& spec) {
const std::tm tm{*std::localtime(&t)}; std::time_t cumulative = spec.tm_year;
cumulative = cumulative * 365 + spec.tm_yday; // Years to days
return fmt::format("{:%z}", tm); cumulative = cumulative * 24 + spec.tm_hour; // Days to hours
} cumulative = cumulative * 60 + spec.tm_min; // Hours to minutes
cumulative = cumulative * 60 + spec.tm_sec; // Minutes to seconds
static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) { return cumulative;
try {
return std::stoi(timezone);
} catch (const std::invalid_argument&) {
LOG_CRITICAL(Common, "invalid_argument with {}!", timezone);
return 0;
} catch (const std::out_of_range&) {
LOG_CRITICAL(Common, "out_of_range with {}!", timezone);
return 0;
}
} }
std::chrono::seconds GetCurrentOffsetSeconds() { std::chrono::seconds GetCurrentOffsetSeconds() {
const int offset{ConvertOsTimeZoneOffsetToInt(GetOsTimeZoneOffset())}; const std::time_t t{std::time(nullptr)};
const std::tm local{*std::localtime(&t)};
const std::tm gmt{*std::gmtime(&t)};
int seconds{(offset / 100) * 60 * 60}; // Convert hour component to seconds // gmt_seconds is a different offset than time(nullptr)
seconds += (offset % 100) * 60; // Convert minute component to seconds const auto gmt_seconds = TmSpecToSeconds(gmt);
const auto local_seconds = TmSpecToSeconds(local);
const auto seconds_offset = gmt_seconds - local_seconds;
return std::chrono::seconds{seconds}; return std::chrono::seconds{seconds_offset};
} }
// Key is [Hours * 100 + Minutes], multiplied by 100 if DST // Key is [Hours * 100 + Minutes], multiplied by 100 if DST
@ -71,11 +66,6 @@ const static std::map<s64, const char*> off_timezones = {
}; };
std::string FindSystemTimeZone() { std::string FindSystemTimeZone() {
#if defined(MINGW)
// MinGW has broken strftime -- https://sourceforge.net/p/mingw-w64/bugs/793/
// e.g. fmt::format("{:%z}") -- returns "Eastern Daylight Time" when it should be "-0400"
return timezones[0];
#else
const s64 seconds = static_cast<s64>(GetCurrentOffsetSeconds().count()); const s64 seconds = static_cast<s64>(GetCurrentOffsetSeconds().count());
const s64 minutes = seconds / 60; const s64 minutes = seconds / 60;
@ -97,7 +87,6 @@ std::string FindSystemTimeZone() {
} }
} }
return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours)); return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours));
#endif
} }
} // namespace Common::TimeZone } // namespace Common::TimeZone