The Timezone library: UTC to local time, daylight saving included
Jack Christensen鈥檚 Timezone library answers one question: given the time in UTC, what does the wall clock say here? Clocks synced from NTP or GPS give UTC, and working out daylight saving by hand is fiddly, so the library takes two rules, one for when summer time starts and one for when standard time returns, and does the conversion.
Built in on Mokxi: #include <Timezone.h> and it builds, with nothing to install. Free, and no account needed.
What Timezone does
A TimeChangeRule is written the way the law states it: a name, the week of the month (First to Fourth, or Last), the day, the month, the local hour of the change, and the offset from UTC in minutes after it. US Eastern is {"EDT", Second, Sun, Mar, 2, -240} and {"EST", First, Sun, Nov, 2, -300}; Central European is {"CEST", Last, Sun, Mar, 2, 120} and {"CET", Last, Sun, Oct, 3, 60}.
It sits on the Time library and uses its time_t, so keep the system clock in UTC and convert only for display. A zone with no daylight saving uses the same rule twice.
| Library Manager name | Timezone |
|---|---|
| Author | Jack Christensen |
| Include | #include <Timezone.h> |
| Boards | every board Mokxi compiles for |
| In the simulator | Simulated: it runs against the part the way it does on the bench. |
Install it
It builds on every board Mokxi compiles for.
In Mokxi it is built in: #include <Timezone.h> and the sketch compiles, with no download, no zip and no Library Manager.
On a real board, install "Timezone" by Jack Christensen from the Arduino IDE鈥檚 Library Manager (Sketch, Include Library, Manage Libraries), or add Timezone to lib_deps in PlatformIO. Mokxi follows the calls of release 1.3.1, so a sketch written here builds there too.
ESP32-C3 路 Arduino Uno 路 Arduino Nano 路 Arduino Mega 2560 路 Arduino Leonardo 路 SparkFun Pro Micro 路 Arduino Micro 路 ESP32-C6 路 ATtiny85 路 Raspberry Pi Pico 路 Raspberry Pi Pico W 路 Seeed XIAO SAMD21 路 STM32 路 STM32 Nucleo-F411RE 路 STM32 Blue Pill 路 micro:bit V2 路 Arduino Uno R4 路 ESP32 DevKit 路 ESP32-S3-DevKitC-1 路 ESP8266 NodeMCU 路 Arduino Pro Mini 3.3 V 路 Seeed XIAO ESP32-C3 路 ESP32-C3 SuperMini 路 Seeed XIAO ESP32-C6 路 ESP32-DevKitC V4 路 LOLIN32 Lite 路 Wemos D1 R32 路 Cheap Yellow Display 路 TTGO T-Display 路 Seeed XIAO ESP32-S3 路 Arduino Nano ESP32 路 Arduino Nano RP2040 Connect 路 Seeed XIAO RP2040 路 Waveshare RP2040-Zero 路 Arduino Uno R4 WiFi
The calls you will use
In the order a sketch meets them.
TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2, -240};
A rule: summer time starts on the second Sunday of March at 2:00 local, 240 minutes behind UTC.
Timezone usEastern(usEDT, usEST);
A zone from its summer-time rule and its standard-time rule, in that order.
time_t local = usEastern.toLocal(now(), &tcr);
Converts a UTC time_t to local time. With a TimeChangeRule pointer, it also says which rule applies, so tcr->abbrev is "EDT" or "EST".
TimeChangeRule *tcr;
time_t local = usEastern.toLocal(now(), &tcr);
Serial.print(hour(local));
Serial.println(tcr->abbrev);usEastern.utcIsDST(now())
True when a UTC time falls in summer time. locIsDST() asks the same of a local time.
usEastern.toUTC(localTime)
Converts a local time back to UTC, for setting a UTC clock from a time a person typed in.
usEastern.setRules(usEDT, usEST)
Swaps in new rules at run time, as when a user picks a different zone.
usEastern.writeRules(100)
Saves the two rules to EEPROM at that address; readRules(100) loads them back after a reset.
Example: US Eastern time from UTC, summer and winter
On the Arduino Uno R3. It runs in the browser exactly as printed.
#include <TimeLib.h>
#include <Timezone.h>
TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2, -240};
TimeChangeRule usEST = {"EST", First, Sun, Nov, 2, -300};
Timezone usEastern(usEDT, usEST);
time_t utcAt(int y, int m, int d, int h) {
tmElements_t tm;
tm.Year = CalendarYrToTm(y);
tm.Month = m;
tm.Day = d;
tm.Hour = h;
tm.Minute = 0;
tm.Second = 0;
return makeTime(tm);
}
void show(time_t utc) {
TimeChangeRule *tcr;
time_t local = usEastern.toLocal(utc, &tcr);
Serial.print(hour(utc));
Serial.print(":00 UTC is ");
Serial.print(hour(local));
Serial.print(":00 ");
Serial.println(tcr->abbrev);
}
void setup() {
Serial.begin(9600);
show(utcAt(2026, 7, 1, 12));
show(utcAt(2026, 1, 15, 12));
// Summer time starts at 2:00 EST on 8 March 2026, which is 7:00 UTC.
show(utcAt(2026, 3, 8, 6));
show(utcAt(2026, 3, 8, 7));
Serial.print("back to UTC ");
Serial.println(hour(usEastern.toUTC(utcAt(2026, 7, 1, 8))));
}
void loop() {}Common errors and how to fix them
The local time is off by exactly one hour for part of the year
One of the rules is wrong: the week, month or hour of the change, or the two rules are passed in the wrong order. The first argument to Timezone is the summer-time rule, the second the standard-time rule.
The local time is off by several hours all year
The system clock is not in UTC. Keep TimeLib set to UTC (NTP and GPS already give UTC) and use toLocal() only for display. Offsets west of Greenwich are negative minutes.
'TimeChangeRule' does not name a type
Timezone.h is missing or the Time library is not installed. Include TimeLib.h and Timezone.h, and install both the Time library and Jack Christensen鈥檚 Timezone library.
Keep going
Try Timezone without installing anything
Open the example, change the sketch, and keep your version in a free account.