API của tôi bị lỗi vào mỗi ngày 1 tháng 1
API của tôi bị lỗi chính xác vào lúc 00:00 UTC ngày 1 tháng 1.
Nó không bị lỗi vào lúc nửa đêm theo giờ của người dùng. Nó bị lỗi vào lúc nửa đêm UTC. Người dùng ở Tokyo đã thấy dữ liệu bị lỗi bắt đầu từ 9 giờ sáng theo giờ địa phương của họ.
Các bài kiểm tra (tests) đều vượt qua. Môi trường staging hoạt động bình thường. Lỗi chỉ xuất hiện ở môi trường production vì máy chủ production sử dụng múi giờ khác với staging.
Vấn đề nằm ở logic này:
function getDailyReport(date) {
const start = new Date(date).toISOString().split('T')[0];
const end = new Date(start + 'T23:59:59Z');
return db.reports.findMany({
where: {
createdAt: { gte: new Date(start), lt: end }
}
});
}
Khi bạn truyền vào một ngày như "2026-01-01" mà không có giờ, hệ thống sẽ sử dụng múi giờ địa phương.
Máy chủ staging của chúng tôi sử dụng UTC. Máy chủ production của chúng tôi sử dụng US-East. Điều này tạo ra sự chênh lệch 5 giờ trong mọi truy vấn ngày tháng.
Chúng tôi đã mất 5 giờ dữ liệu trong mỗi truy vấn. Các con số trông có vẻ đủ gần nên không ai nhận ra trong suốt một năm trời.
Cách khắc phục rất đơn giản. Ép buộc sử dụng UTC bằng cách thêm giờ vào chuỗi:
function getDailyReport(date: string) {
const start = new Date(`${date}T00:00:00Z`);
const end = new Date(`${date}T23:59:59.999Z`);
return db.reports.findMany({
where: {
createdAt: { gte: start, lt: end }
}
});
}
Việc thay đổi mã nguồn chỉ mất vài giây. Nhưng việc khắc phục hệ thống lại mất cả tuần. Chúng tôi đã thực hiện bốn việc sau:
• Thêm một bước xác nhận múi giờ (timezone assertion) trong CI để đảm bảo môi trường luôn ở chế độ UTC.
• Thiết lập TZ=UTC trong tất cả các Dockerfile để giữ cho mọi container đồng nhất.
• Thêm bước kiểm tra múi giờ vào script triển khai (deploy script).
• Viết một quy tắc linter để cảnh báo bất kỳ hàm khởi tạo Date nào thiếu thông tin múi giờ.
Lỗi múi giờ rất nguy hiểm. Chúng không làm sập hệ thống của bạn. Chúng tạo ra dữ liệu sai nhưng trông có vẻ chính xác. Người dùng của bạn sẽ không thấy trang báo lỗi. Họ sẽ thấy những con số sai lệch và họ sẽ tin vào chúng.
Hãy tuân thủ ba quy tắc sau:
- Đừng bao giờ tin tưởng vào múi giờ của hệ thống. Luôn thiết lập
TZ=UTC. - Đừng bao giờ phân tích (parse) ngày tháng mà không có múi giờ.
- Đừng bao giờ giả định rằng múi giờ của CI khớp với production.