Thư viện TimeLib: xử lý timezone và DST trên Arduino
TimeLib (Time by Michael Margolis) là thư viện xử lý thời gian phổ biến nhất cho Arduino. Nó cho phép set, get, format thời gian — kết hợp với RTC hoặc NTP để có giờ thật. Bài này hướng dẫn API, timezone Việt Nam (UTC+7), và xử lý DST cho dự án quốc tế.
1. TimeLib hoạt động thế nào?
TimeLib lưu giờ dưới dạng Unix timestamp — số giây từ 1/1/1970. Mọi format (giờ, phút, ngày, tháng) tính từ đó. Hoạt động trên mọi Arduino — chỉ là math, không cần phần cứng.
Tuy nhiên trên ESP32, nên dùng time.h của ESP-IDF (có sẵn) — hỗ trợ timezone string đầy đủ và NTP tự sync. Bài này giới thiệu cả 2.
2. Cài TimeLib
Library Manager → "Time" by Michael Margolis. Không có dependency.
3. API cơ bản TimeLib
#include
void setup() {
Serial.begin(115200);
// Set time manually (timestamp 1717000000 = 2024-05-29 12:53:20 UTC)
setTime(1717000000);
}
void loop() {
Serial.printf("%04d-%02d-%02d %02d:%02d:%02d\n",
year(), month(), day(), hour(), minute(), second());
delay(1000);
}
Các hàm chính:
setTime(epoch)— đặt giờ.year() month() day() hour() minute() second()— đọc hiện tại.now()— Unix timestamp.weekday()— 1 (Sun) đến 7 (Sat).dayShortStr(n),monthShortStr(n)— string.
4. Sync với NTP (ESP32)
Cách native trên ESP32:
#include
#include
void setup() {
Serial.begin(115200);
WiFi.begin("SSID", "PASS");
while (WiFi.status() != WL_CONNECTED) delay(500);
// Vietnam: UTC+7, no DST
configTime(7 * 3600, 0, "pool.ntp.org", "asia.pool.ntp.org");
delay(1000);
}
void loop() {
struct tm t;
if (getLocalTime(&t)) {
char buf[32];
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &t);
Serial.println(buf);
}
delay(1000);
}
5. Timezone với POSIX TZ string
Cách "chuẩn" để xử lý timezone + DST:
// Vietnam: ICT+7, no DST
setenv("TZ", "ICT-7", 1);
tzset();
// New York: EST/EDT with DST rules
setenv("TZ", "EST5EDT,M3.2.0,M11.1.0", 1);
tzset();
// London: GMT/BST
setenv("TZ", "GMT0BST,M3.5.0/1,M10.5.0", 1);
tzset();
// Japan: JST+9 no DST
setenv("TZ", "JST-9", 1);
tzset();
POSIX TZ format: <STD><offset>[<DST>[/offset]][,Mm.w.d[/time],Mm.w.d[/time]]. Phức tạp nhưng powerful — system tự xử lý DST switch tự động.
6. Format time
// strftime — chuẩn C
char buf[64];
time_t t = time(nullptr);
struct tm* tm_info = localtime(&t);
strftime(buf, 64, "%H:%M:%S", tm_info); // 14:30:55
strftime(buf, 64, "%A %d/%m/%Y", tm_info); // Wednesday 29/05/2024
strftime(buf, 64, "%Y-%m-%dT%H:%M:%S", tm_info); // ISO 8601
Serial.println(buf);
Một số format code:
%Y— năm 4 số.%m— tháng 01-12.%d— ngày 01-31.%H/%I— giờ 24h / 12h.%M— phút.%S— giây.%A/%a— thứ full / 3 chữ.%B/%b— tháng full / 3 chữ.
7. Tính khoảng cách thời gian
// 2 timestamp
time_t now = time(nullptr);
time_t target;
struct tm t = {};
t.tm_year = 2026 - 1900;
t.tm_mon = 0; // 0 = January
t.tm_mday = 1;
target = mktime(&t);
long diff_sec = target - now;
int days = diff_sec / 86400;
Serial.printf("Tet 2026: con %d ngay\n", days);
8. RTC backup khi mất WiFi (DS3231)
NTP cần WiFi. Khi mất WiFi, có thể lấy giờ từ RTC. Cài thêm thư viện RTClib:
#include
RTC_DS3231 rtc;
void setup() {
rtc.begin();
if (rtc.lostPower()) {
// RTC mất điện hoặc lần đầu
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // dùng giờ compile
}
}
void loop() {
DateTime now = rtc.now();
Serial.printf("%04d-%02d-%02d %02d:%02d:%02d\n",
now.year(), now.month(), now.day(),
now.hour(), now.minute(), now.second());
delay(1000);
}
Pattern: ESP32 boot → cố sync NTP. Thành công → set RTC. Mất WiFi → đọc RTC.
9. Cron-like scheduling
Bật relay mỗi ngày 7h sáng:
void loop() {
struct tm t;
if (!getLocalTime(&t)) return;
static int lastTrigger = -1;
// Sáng 7h, chỉ trigger 1 lần
if (t.tm_hour == 7 && t.tm_min == 0 && t.tm_yday != lastTrigger) {
lastTrigger = t.tm_yday;
digitalWrite(RELAY, HIGH);
Serial.println("Morning trigger!");
}
}
Lưu tm_yday (day of year) làm anti-double-trigger.
10. Múi giờ một số nước
| Quốc gia | POSIX TZ |
|---|---|
| Việt Nam | ICT-7 |
| Thái Lan | ICT-7 |
| Nhật Bản | JST-9 |
| Hàn Quốc | KST-9 |
| Trung Quốc (cả nước) | CST-8 |
| Singapore | SGT-8 |
| UK | GMT0BST,M3.5.0/1,M10.5.0 |
| US East | EST5EDT,M3.2.0,M11.1.0 |
| US Pacific | PST8PDT,M3.2.0,M11.1.0 |
| Đức / Pháp | CET-1CEST,M3.5.0,M10.5.0/3 |
11. Lỗi thường gặp
- getLocalTime() return false: chưa sync NTP, chờ vài giây sau khi
configTime(). - Giờ lệch 7 tiếng: quên config timezone hoặc dùng offset sai (25200 thay vì 7).
- RTC trôi 5 phút/tháng: dùng DS3231 (TCXO) thay vì DS1307 cơ bản.
- Năm 2038: time_t 32-bit overflow. ESP32 dùng 64-bit, an toàn.
Liên quan
Áp dụng dự án Đồng hồ NTP ESP32 + OLED hoặc Đồng hồ báo thức OLED + DS3231. Đọc bài ESP32 deep sleep để wake theo lịch.