Time zone trong rails và postgresql có gì nổi bật ?

1. Mô tả

Time zone được hiểu là thời gian phân chia theo các múi giờ các nhau. Vậy thì việc xử lý time zone trong rails và postgresql như thế nào thì ta có bối cảnh như sau
Ví dụ:

      Model.where("date(created_at) = ?", Time.zone.now) 

Câu lệnh này dễ hiểu là tìm ra tất cả những record của Model được tạo ra vào ngày hôm nay. Thoạt nhìn, câu lệnh có vẻ đúng nhưng vào một vài múi giờ đặc sắc thì câu lệnh lại cho kết quả sai.
tình thế ở nhật, tạo @record cho Model vào lúc 1h sáng ngày hôm nay thì theo lý thuyết, câu query trên sẽ phải tìm được 1 bản ghi @record. Nhưng sự thật là ta không tìm được nó. Vậy điều gì đã diễn ra ? ta cùng tìm hiểu ở những phần sau đây.

2. Xử lý Time.zone

2.1 Cài đặt

Để trực quan, trước hết ta tạo một model Remider như sau

set up time.zone là giờ nhật

tạo 1 bản ghi

Việc ta viết câu lệnh đối với Time.zone thì rất dễ hiểu, nhưng Postgresql viết Time.zone như thế nào, liệu rằng cũng là JST + 09:00 như trên hình hay là có cách viết nào khác thì ta thử làm thao tác sau:

Có thể nhìn thấy, ta dùng câu lệnh Time.zone.parse(‘2014-08-21 10:30am’) tức là 10:30am theo giờ nhật thì postgresql ghi là:

UPDATE "reminders" SET "created_at" = $1, "updated_at" = $2 WHERE "reminders"."id" = $3  [["created_at", "2014-08-21 01:30:00"], ["updated_at", "2017-09-21 11:11:10.710348"], ["id", 1]] 

"2014-08-21 01:30:00" là giờ quy đổi từ time.zone sang giờ UTC (tức là múi giờ +0)

2.2 giải quyết lỗi đối với Time.zone

a. Tái hiện lỗi

Vậy giờ đây ta sẽ tái hiện lại lỗi như đã mô tả ở trên:

update Reminder.first là 1h30 sáng ngày hôm nay (Time.zone.now) tìm kiếm tất cả những bản ghi được tạo ra với date là ngày hôm nay.
Kết quả:

Nhưng với 1 ngày trước:

Với những ví dụ ở trên thì ta có thể giải thích kết quả trả về như sau:
Postgresql không giúp đỡ tìm kiếm thời gian theo zone (nếu như ta không chỉ định nó). Mà nó sẽ tự động convert ngày theo time.zone về ngày giờ theo UTC. vì múi giờ nhật là múi giờ + 9 nên ta sẽ lấy thời gian Time.zone trừ đi 9h.
Do đó date(created_at) lúc này thực chất sẽ được hiểu là date của 1 ngày trước. Bởi vậy việc tìm kiếm nó với Time.zone.now sẽ không cho ra kết quả.

b. giải quyết

Để Postgresql hiểu được zone, ta cần chỉ định cho nó hiểu trong câu query của mình như sau:
ta convert created_at thành giờ UTC tiếp nữa đối chiếu với Time.zone.now:

3. Kết luận

Việc dùng Time.zone trong postgresql là khá phổ biến, nhất là với những dự án mà phạm vi làm việc của người sử dụng là đa quốc gia. Bởi vậy qua bài viết, mong rằng ta sẽ có thêm kinh nghiệm khi dùng nó để tránh gặp những lỗi giống như như trên.

4. Tài liệu tham khảo

http://brendankemp.com/essays/dealing-with-time-zones-using-rails-and-postgres/

Nguồn viblo.asia