12/08/2018, 16:01

Time zone trong rails và postgresql có gì đặc biệ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ì chúng ta có bối cảnh như sau Ví dụ: Model.where("date(created_at) = ?", Time.zone.now) Câu lệnh này đơn giản là tìm ra tất cả những ...

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ì chúng ta có bối cảnh như sau Ví dụ:
      Model.where("date(created_at) = ?", Time.zone.now)

Câu lệnh này đơn giản 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 số múi giờ đặc biệt thì câu lệnh lại cho kết quả sai. Trường hợp ở 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à chúng ta không tìm được nó. Vậy điều gì đã xảy ra ? Chúng ta cùng tìm hiểu ở những phần dưới đâ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 chúng ta viết câu lệnh đối với Time.zone thì rất đơn giản, 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ì chúng ta thử làm thao tác sau:

  • Có thể nhìn thấy, chúng ta sử 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 Khắc phục lỗi đối với Time.zone

a. Tái hiện lỗi

Vậy bây giờ chúng 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ì chúng ta có thể giải thích kết quả trả về như sau: Postgresql không hỗ trợ tìm kiếm thời gian theo zone (nếu như chúng 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 chúng 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. Khắc phục

Để Postgresql hiểu được zone, chúng ta cần chỉ định cho nó hiểu trong câu query của mình như sau: chúng ta convert created_at thành giờ UTC sau đó so sánh với Time.zone.now:

3. Kết luận

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

4.

0