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:
parent
e32ce6cc69
commit
90d76333da
|
@ -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
|
||||||
|
|
Reference in New Issue