diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index d3f39c377b..16906e2e06 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -99,7 +99,7 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) // If we are the first message on a report, include the header if (!isContinuationMessage) { - uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice); + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile if (rtc_sec > 0) { long hms = rtc_sec % SEC_PER_DAY; // hms += tz.tz_dsttime * SEC_PER_HOUR; diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index 10e9e0331d..58b267a6cd 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -128,7 +128,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv) #else rtc.initI2C(); #endif - tm *t = localtime(&tv->tv_sec); + tm *t = gmtime(&tv->tv_sec); rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec); @@ -142,7 +142,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv) #else rtc.begin(); #endif - tm *t = localtime(&tv->tv_sec); + tm *t = gmtime(&tv->tv_sec); rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec); @@ -175,7 +175,15 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t) The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z). */ + // horrible hack to make mktime TZ agnostic - best practise according to + // https://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html + setenv("TZ", "GMT0", 1); time_t res = mktime(&t); + if (*config.device.tzdef) { + setenv("TZ", config.device.tzdef, 1); + } else { + setenv("TZ", "UTC0", 1); + } struct timeval tv; tv.tv_sec = res; tv.tv_usec = 0; // time.centisecond() * (10 / 1000); @@ -189,14 +197,33 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t) } } +/** + * Returns the timezone offset in seconds. + * + * @return The timezone offset in seconds. + */ +int32_t getTZOffset() +{ + time_t now; + struct tm *gmt; + now = time(NULL); + gmt = gmtime(&now); + gmt->tm_isdst = -1; + return (int16_t)difftime(now, mktime(gmt)); +} + /** * Returns the current time in seconds since the Unix epoch (January 1, 1970). * * @return The current time in seconds since the Unix epoch. */ -uint32_t getTime() +uint32_t getTime(bool local) { - return (((uint32_t)millis() - timeStartMsec) / 1000) + zeroOffsetSecs; + if (local) { + return (((uint32_t)millis() - timeStartMsec) / 1000) + zeroOffsetSecs + getTZOffset(); + } else { + return (((uint32_t)millis() - timeStartMsec) / 1000) + zeroOffsetSecs; + } } /** @@ -205,7 +232,7 @@ uint32_t getTime() * @param minQuality The minimum quality of the RTC time required for it to be considered valid. * @return The current time from the RTC if it meets the minimum quality requirement, or 0 if the time is not valid. */ -uint32_t getValidTime(RTCQuality minQuality) +uint32_t getValidTime(RTCQuality minQuality, bool local) { - return (currentQuality >= minQuality) ? getTime() : 0; + return (currentQuality >= minQuality) ? getTime(local) : 0; } diff --git a/src/gps/RTC.h b/src/gps/RTC.h index 527b31f46a..f74e17cd0a 100644 --- a/src/gps/RTC.h +++ b/src/gps/RTC.h @@ -29,10 +29,10 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv); bool perhapsSetRTC(RTCQuality q, struct tm &t); /// Return time since 1970 in secs. While quality is RTCQualityNone we will be returning time based at zero -uint32_t getTime(); +uint32_t getTime(bool local = false); /// Return time since 1970 in secs. If quality is RTCQualityNone return zero -uint32_t getValidTime(RTCQuality minQuality); +uint32_t getValidTime(RTCQuality minQuality, bool local = false); void readFromRTC(); diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 11c0b7aa09..e5f3920368 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1896,7 +1896,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat // Show uptime as days, hours, minutes OR seconds std::string uptime = screen->drawTimeDelta(days, hours, minutes, seconds); - uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice); + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // Display local timezone if (rtc_sec > 0) { long hms = rtc_sec % SEC_PER_DAY; // hms += tz.tz_dsttime * SEC_PER_HOUR; diff --git a/src/main.cpp b/src/main.cpp index e93acf0ffc..47f3e2c22d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -663,6 +663,15 @@ void setup() // Initialize the screen first so we can show the logo while we start up everything else. screen = new graphics::Screen(screen_found, screen_model, screen_geometry); + // setup TZ prior to time actions. + if (*config.device.tzdef) { + setenv("TZ", config.device.tzdef, 1); + } else { + setenv("TZ", "GMT0", 1); + } + tzset(); + LOG_DEBUG("Set Timezone to %s\n", getenv("TZ")); + readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time) #if !MESHTASTIC_EXCLUDE_GPS