Sming icon indicating copy to clipboard operation
Sming copied to clipboard

[WIP] Add timezone check callback to SystemClock

Open mikee47 opened this issue 2 months ago • 0 comments

This PR adds a simple mechanism to ensure the SystemClock timezone offset can be maintained efficiently.

Obtaining the local time involves converting the current system clock time from UTC using an offset based on the currently active timezone rules. The Timezone library is one way to deal with this, but not the only way of course.

There is currently no mechanism for keeping the system clock time offset correct, other than periodically setting it. For example, this is how the SystemClock_NTP sample currently does it. However, that's not ideal since we might only need to update via NTP infrequently; the two tasks aren't actually related.

This is the code added to the SystemClock_NTP sample, in the NtpClientDemo.cpp file:

void checkTimeZoneOffset(time_t systemTime)
{
	static time_t nextChange;
	static const TimeChangeRule* rule;

	if(!rule) {
		tz.toLocal(systemTime, &rule);
	} else if(systemTime < nextChange) {
                // For most calls we just return
		return;
	}

        // This happens on first call, or if switching from DST to STD or vice-versa (twice a year!)
	SystemClock.setTimeZoneOffset(rule->offset * SECS_PER_MIN);
	nextChange = tz.getNextChange(systemTime, &rule);
}

It's important to note that the system clock must be correctly set before this is called for the first time. Therefore the call to SystemClock.onCheckTimeZoneOffset(checkTimeZoneOffset) is made only after setting the clock in our NTP callback. From then on, checkTimeZoneOffset is called whenever the local time is requested from SystemClock.

It's efficient because we note when the next change to/from DST is and so only need to check it, but will guarantee that the correct local time is returned without having to perform a full TimeChangeRule calculation every time.

On a related note, C library support for timezone generally involves code like this:

setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3");
tzset();

This works for Host and Esp32, but not for Rp2040 or Esp8266 as those toolchains have libraries built without this support. Localisation can be expensive!

mikee47 avatar Apr 23 '24 19:04 mikee47