Ngày giờ khó trong lập trình vì cùng một khoảnh khắc lại có giờ khác nhau ở mỗi nơi, nhiều nước đổi giờ theo mùa, và chữ hôm nay phụ thuộc vào người dùng đang đứng ở đâu. Nguyên tắc an toàn là lưu thời điểm theo giờ chuẩn quốc tế và chỉ đổi sang giờ địa phương vào lúc hiện ra cho người xem.
Chào bạn, đây là Nhà Lập Trình. Nếu hỏi người làm nghề lâu năm loại lỗi nào họ sợ nhất, rất nhiều người sẽ nhắc tới ngày giờ. Nó trông đơn giản, ai mà chẳng biết xem đồng hồ. Nhưng nó chứa đầy những cái bẫy mà chỉ khi rơi vào bạn mới biết. Tập này mình kể vài cái bẫy quen thuộc nhất.
Một khoảnh khắc, nhiều cái giờ
Lúc bạn nghe tập này, ở Việt Nam là một giờ nào đó, ở châu Âu là giờ khác, ở Mỹ lại là giờ khác nữa, có khi còn khác ngày. Nhưng đó vẫn là cùng một khoảnh khắc. Máy tính cần phân biệt rõ hai thứ: khoảnh khắc thật, và cách một nơi cụ thể gọi tên khoảnh khắc đó.
Lỗi kinh điển là lưu giờ mà không lưu nó là giờ ở đâu. Cơ sở dữ liệu ghi mười giờ sáng. Mười giờ sáng ở đâu? Nếu máy chủ đặt ở nước ngoài và ghi theo giờ của nó, còn người đọc ở Việt Nam hiểu theo giờ Việt Nam, mọi đơn hàng đều lệch vài tiếng.
Cách làm mà hầu hết người trong nghề thống nhất là lưu mọi thời điểm theo giờ chuẩn quốc tế, một thứ giờ không đổi theo nơi, không đổi theo mùa. Khi hiện ra cho ai xem, mới đổi sang giờ của người đó.
Nghe đơn giản, nhưng nó đòi hỏi mọi thành phần trong hệ thống đều tuân thủ. Một đoạn mã cũ nào đó lấy giờ của máy chủ thay vì giờ chuẩn là đủ để gây lệch.
Đổi giờ theo mùa và cái giờ không tồn tại
Việt Nam không đổi giờ theo mùa, nên lập trình viên Việt ít gặp cái bẫy này, cho tới khi làm phần mềm cho khách nước ngoài. Ở nhiều nước, mỗi năm có một đêm đồng hồ nhảy lên một tiếng và một đêm lùi lại một tiếng.
Đêm nhảy lên, có một khoảng giờ hoàn toàn không tồn tại. Nếu ai đó đặt lịch báo thức vào khoảng đó, phần mềm phải quyết định làm gì. Đêm lùi lại, có một khoảng giờ xảy ra hai lần. Một giao dịch lúc một giờ rưỡi sáng là lần thứ nhất hay lần thứ hai?
Quy tắc đổi giờ lại do chính phủ các nước quyết định và có thể thay đổi. Vì vậy các hệ điều hành và ngôn ngữ lập trình dùng một cơ sở dữ liệu múi giờ được cập nhật thường xuyên. Máy chủ lâu không cập nhật có thể tính sai giờ ở một nước vừa đổi quy tắc.
Bài học ở đây là đừng tự viết phép tính cộng trừ giờ bằng tay. Hãy dùng thư viện ngày giờ có sẵn của ngôn ngữ, vì người viết thư viện đã vấp hết những cái bẫy này thay bạn.
Hôm nay là ngày nào?
Câu hỏi hôm nay là ngày nào nghe ngớ ngẩn, nhưng với phần mềm nó không có câu trả lời duy nhất. Lúc sáu giờ sáng ở Việt Nam, ở châu Âu vẫn còn là đêm hôm trước. Lúc mười một giờ đêm ở Việt Nam, ở những nơi phía đông xa hơn đã sang ngày mới.
Chuyện này gây lỗi ở những chỗ không ngờ. Lấy báo cáo doanh thu theo ngày làm ví dụ. Giờ Việt Nam đi trước giờ chuẩn quốc tế bảy tiếng. Một đơn hàng lúc sáu giờ sáng theo giờ Việt Nam, nếu máy chủ chia ngày theo giờ chuẩn, sẽ bị tính vào ngày hôm trước. Mọi đơn từ nửa đêm tới bảy giờ sáng đều rơi nhầm ngày, và báo cáo cuối tháng lệch hẳn một khúc.
Hạn chót cũng vậy. Bạn thông báo hạn nộp bài là hết ngày mười lăm. Hết ngày mười lăm theo giờ nào? Học viên ở nước ngoài nộp lúc mười giờ tối giờ của họ, theo giờ Việt Nam đã sang ngày mười sáu. Họ bị tính trễ và rất bức xúc.
Cách xử lý là khi nói tới ngày, luôn rõ ngày theo múi giờ nào. Báo cáo cho công ty ở Việt Nam thì chia ngày theo giờ Việt Nam. Hạn chót cho người dùng toàn cầu thì ghi rõ múi giờ, hoặc dùng một khoảnh khắc chính xác.
Những ngày tháng đặc biệt của người Việt
Phần mềm cho người Việt còn có vài đòi hỏi riêng. Lịch âm là thứ đầu tiên. Ngày giỗ, ngày rằm, ngày Tết, sinh nhật theo âm lịch của ông bà. Đổi lịch dương sang âm không đơn giản như cộng trừ, vì âm lịch có tháng nhuận, có tháng thiếu tháng đủ, và cần tính theo giờ Việt Nam.
Cách viết ngày cũng khác. Người Việt viết ngày trước tháng sau, người Mỹ viết tháng trước ngày sau. Ngày mồng năm tháng ba và ngày mồng ba tháng năm viết ra có thể giống nhau. Khi nhận dữ liệu từ tệp bảng tính, đoán sai định dạng là lẫn lộn cả nghìn dòng mà không báo lỗi gì, vì ngày nào cũng hợp lệ nếu nhỏ hơn mười ba.
Và đừng quên tuần làm việc. Có nơi làm thứ bảy, có nơi không. Có ngày nghỉ lễ thay đổi theo từng năm. Phần mềm tính ngày giao hàng hay ngày đến hạn cần một danh sách ngày nghỉ cập nhật được, chứ không thể viết cứng.
Mỗi chi tiết nhỏ này đều là một lời phàn nàn của người dùng nếu bạn bỏ qua.
Vài nguyên tắc để ngủ ngon hơn
Nguyên tắc thứ nhất: lưu khoảnh khắc theo giờ chuẩn quốc tế, kèm thông tin múi giờ khi cần. Nguyên tắc thứ hai: đổi sang giờ địa phương ở lớp hiển thị, càng gần người xem càng tốt.
Nguyên tắc thứ ba: phân biệt khoảnh khắc với ngày lịch. Sinh nhật là một ngày lịch, không phải một khoảnh khắc, nó không nên dịch chuyển theo múi giờ. Lưu sinh nhật như một khoảnh khắc rồi đổi múi giờ là cách nhanh nhất để chúc mừng sinh nhật người ta sớm một ngày.
Nguyên tắc thứ tư: dùng thư viện ngày giờ, đừng tự tính. Nguyên tắc thứ năm: thử nghiệm với những thời điểm gần nửa đêm, gần giao thừa, ngày hai mươi chín tháng hai, và với người dùng ở múi giờ khác.
Ngày giờ dạy cho người lập trình một bài học khiêm tốn: những thứ con người coi là hiển nhiên thường chứa nhiều quy ước ngầm nhất. Và máy tính thì không hiểu quy ước ngầm.
Câu hỏi thường gặp
Nên lưu giờ trong cơ sở dữ liệu theo giờ Việt Nam hay giờ chuẩn quốc tế?
Nên lưu theo giờ chuẩn quốc tế và đổi sang giờ Việt Nam khi hiển thị. Cách này tránh nhầm lẫn khi máy chủ đặt ở nước khác hoặc khi hệ thống phục vụ người dùng ở nhiều múi giờ.
Việt Nam có đổi giờ theo mùa không?
Hiện nay Việt Nam không đổi giờ theo mùa. Nhưng nếu phần mềm có người dùng hoặc máy chủ ở nước khác, bạn vẫn phải xử lý chuyện đổi giờ của những nơi đó.
Vì sao báo cáo doanh thu theo ngày bị lệch?
Thường do hệ thống chia ngày theo giờ chuẩn quốc tế hoặc giờ máy chủ thay vì giờ Việt Nam. Các đơn hàng gần nửa đêm hoặc sáng sớm bị tính sang ngày khác.
Làm sao lưu sinh nhật cho đúng?
Lưu sinh nhật như một ngày lịch gồm ngày, tháng, năm, không kèm giờ và múi giờ. Nếu lưu như một khoảnh khắc rồi đổi múi giờ, ngày có thể bị lùi hoặc tiến một ngày.
Phần mềm tính lịch âm có khó không?
Khá phức tạp vì âm lịch có tháng nhuận, tháng đủ thiếu và phụ thuộc thời điểm thiên văn tính theo giờ Việt Nam. Nên dùng thư viện đã được kiểm chứng thay vì tự viết.