summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/settings.cpp3
-rw-r--r--src/common/time_zone.cpp47
2 files changed, 21 insertions, 29 deletions
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 5972480e5..d4e55f988 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -26,7 +26,8 @@ std::string GetTimeZoneString() {
26 26
27 std::string location_name; 27 std::string location_name;
28 if (time_zone_index == 0) { // Auto 28 if (time_zone_index == 0) { // Auto
29#if __cpp_lib_chrono >= 201907L 29#if __cpp_lib_chrono >= 201907L && !defined(MINGW)
30 // Disabled for MinGW -- tzdb always returns Etc/UTC
30 try { 31 try {
31 const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb(); 32 const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
32 const std::chrono::time_zone* current_zone = time_zone_data.current_zone(); 33 const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
diff --git a/src/common/time_zone.cpp b/src/common/time_zone.cpp
index d8d7896c6..69e728a9d 100644
--- a/src/common/time_zone.cpp
+++ b/src/common/time_zone.cpp
@@ -4,13 +4,13 @@
4#include <chrono> 4#include <chrono>
5#include <exception> 5#include <exception>
6#include <iomanip> 6#include <iomanip>
7#include <map>
7#include <sstream> 8#include <sstream>
8#include <stdexcept> 9#include <stdexcept>
9#include <fmt/chrono.h> 10#include <fmt/chrono.h>
10#include <fmt/core.h> 11#include <fmt/core.h>
11 12
12#include "common/logging/log.h" 13#include "common/logging/log.h"
13#include "common/settings.h"
14#include "common/time_zone.h" 14#include "common/time_zone.h"
15 15
16namespace Common::TimeZone { 16namespace Common::TimeZone {
@@ -33,32 +33,29 @@ std::string GetDefaultTimeZone() {
33 return "GMT"; 33 return "GMT";
34} 34}
35 35
36static std::string GetOsTimeZoneOffset() { 36// Results are not comparable to seconds since Epoch
37 const std::time_t t{std::time(nullptr)}; 37static std::time_t TmSpecToSeconds(const struct std::tm& spec) {
38 const std::tm tm{*std::localtime(&t)}; 38 const int year = spec.tm_year - 1; // Years up to now
39 39 const int leap_years = year / 4 - year / 100;
40 return fmt::format("{:%z}", tm); 40 std::time_t cumulative = spec.tm_year;
41} 41 cumulative = cumulative * 365 + leap_years + spec.tm_yday; // Years to days
42 42 cumulative = cumulative * 24 + spec.tm_hour; // Days to hours
43static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) { 43 cumulative = cumulative * 60 + spec.tm_min; // Hours to minutes
44 try { 44 cumulative = cumulative * 60 + spec.tm_sec; // Minutes to seconds
45 return std::stoi(timezone); 45 return cumulative;
46 } catch (const std::invalid_argument&) {
47 LOG_CRITICAL(Common, "invalid_argument with {}!", timezone);
48 return 0;
49 } catch (const std::out_of_range&) {
50 LOG_CRITICAL(Common, "out_of_range with {}!", timezone);
51 return 0;
52 }
53} 46}
54 47
55std::chrono::seconds GetCurrentOffsetSeconds() { 48std::chrono::seconds GetCurrentOffsetSeconds() {
56 const int offset{ConvertOsTimeZoneOffsetToInt(GetOsTimeZoneOffset())}; 49 const std::time_t t{std::time(nullptr)};
50 const std::tm local{*std::localtime(&t)};
51 const std::tm gmt{*std::gmtime(&t)};
57 52
58 int seconds{(offset / 100) * 60 * 60}; // Convert hour component to seconds 53 // gmt_seconds is a different offset than time(nullptr)
59 seconds += (offset % 100) * 60; // Convert minute component to seconds 54 const auto gmt_seconds = TmSpecToSeconds(gmt);
55 const auto local_seconds = TmSpecToSeconds(local);
56 const auto seconds_offset = local_seconds - gmt_seconds;
60 57
61 return std::chrono::seconds{seconds}; 58 return std::chrono::seconds{seconds_offset};
62} 59}
63 60
64// Key is [Hours * 100 + Minutes], multiplied by 100 if DST 61// Key is [Hours * 100 + Minutes], multiplied by 100 if DST
@@ -71,11 +68,6 @@ const static std::map<s64, const char*> off_timezones = {
71}; 68};
72 69
73std::string FindSystemTimeZone() { 70std::string FindSystemTimeZone() {
74#if defined(MINGW)
75 // MinGW has broken strftime -- https://sourceforge.net/p/mingw-w64/bugs/793/
76 // e.g. fmt::format("{:%z}") -- returns "Eastern Daylight Time" when it should be "-0400"
77 return timezones[0];
78#else
79 const s64 seconds = static_cast<s64>(GetCurrentOffsetSeconds().count()); 71 const s64 seconds = static_cast<s64>(GetCurrentOffsetSeconds().count());
80 72
81 const s64 minutes = seconds / 60; 73 const s64 minutes = seconds / 60;
@@ -97,7 +89,6 @@ std::string FindSystemTimeZone() {
97 } 89 }
98 } 90 }
99 return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours)); 91 return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours));
100#endif
101} 92}
102 93
103} // namespace Common::TimeZone 94} // namespace Common::TimeZone