CodeGym /Các khóa học /SQL SELF /Làm việc với múi giờ: TIMEZONE

Làm việc với múi giờ: TIMEZONE

SQL SELF
Mức độ, Bài học
Có sẵn

Giả sử bạn có một app đặt vé máy bay. Chuyến bay cất cánh từ New York lúc 10:00 giờ địa phương và hạ cánh ở London lúc 22:00 giờ địa phương. Nếu không để ý đến múi giờ, server của bạn có thể biến mọi thứ thành một mớ hỗn độn, hiển thị sai giờ hạ cánh.

Múi giờ — đúng kiểu bạn thân chí cốt (hoặc kẻ thù truyền kiếp khi mọi thứ không như ý). Nếu user của bạn ở nhiều quốc gia khác nhau hoặc bạn cần làm việc với lịch trình phụ thuộc vào giờ địa phương (kiểu như giờ bay hoặc lịch sự kiện), thì việc xử lý múi giờ là cực kỳ quan trọng luôn.

Các loại dữ liệu thời gian

Bọn mình đã nói qua rồi, có hai loại dữ liệu để làm việc với dấu thời gian:

  • TIMESTAMP: ngày và giờ không có múi giờ.
  • TIMESTAMPTZ: ngày và giờ có múi giờ.

Cùng xem lại ví dụ cho dễ hiểu nhé.

-- Tạo bảng với hai cột: TIMESTAMP và TIMESTAMPTZ
CREATE TABLE flight_schedule (
    flight_id SERIAL PRIMARY KEY,
    departure_time TIMESTAMP,
    departure_time_with_tz TIMESTAMPTZ
);

-- Thêm dữ liệu
INSERT INTO flight_schedule (departure_time, departure_time_with_tz)
VALUES
    ('2023-10-25 10:00:00', '2023-10-25 10:00:00+00');

-- Kiểm tra dữ liệu
SELECT * FROM flight_schedule;

Kết quả sẽ phụ thuộc vào múi giờ của server bạn. Ví dụ:

flight_id departure_time departure_time_with_tz
1 2023-10-25 10:00:00 2023-10-25 10:00:00+00

Điểm khác biệt chính:

  • Cột departure_time chỉ lưu ngày và giờ mà không gắn với bất kỳ múi giờ nào.
  • Cột departure_time_with_tz lưu ngày và giờ kèm thông tin múi giờ (+00 trong ví dụ này).

Chuyển đổi thời gian giữa các múi giờ

Để làm việc với múi giờ trong PostgreSQL, bạn dùng hàm AT TIME ZONE.

Chuyển đổi UTC sang giờ địa phương

Giả sử bạn có một dấu thời gian ở định dạng UTC (giờ phối hợp quốc tế). Bạn muốn hiển thị nó cho user ở múi giờ America/New_York.

SELECT
    '2023-10-25 14:00:00+00'::TIMESTAMPTZ AT TIME ZONE 'America/New_York' AS local_time;

Kết quả:

local_time
2023-10-25 10:00:00

AT TIME ZONE ở đây như kiểu phép thuật: nó chuyển đổi thời gian từ UTC sang múi giờ bạn chỉ định.

Chuyển đổi giờ địa phương sang UTC

Giờ thử bài toán ngược lại: bạn có thời gian ở America/New_York, và muốn chuyển nó sang UTC.

SELECT
    '2023-10-25 10:00:00'::TIMESTAMP AT TIME ZONE 'America/New_York' AS utc_time;

Kết quả:

utc_time
2023-10-25 14:00:00+00

Lưu ý là kết quả sẽ ở dạng TIMESTAMPTZ, vì nó bao gồm thông tin về múi giờ (UTC trong trường hợp này).

Làm việc với kiểu dữ liệu TIMESTAMPTZ

Khi bạn dùng TIMESTAMPTZ, PostgreSQL sẽ tự động tính đến múi giờ của server (hoặc múi giờ bạn set).

Bạn có thể set múi giờ cho session hiện tại bằng lệnh:

SET TIMEZONE = 'Europe/Istanbul';

Sau đó mọi thao tác với TIMESTAMPTZ sẽ dựa trên múi giờ này.

Ví dụ: thêm và lấy dữ liệu

-- Set múi giờ
SET TIMEZONE = 'Europe/Istanbul';

-- Thêm dữ liệu
INSERT INTO flight_schedule (departure_time_with_tz)
VALUES ('2023-10-25 10:00:00+00');

-- Kiểm tra dữ liệu
SELECT departure_time_with_tz FROM flight_schedule;

Kết quả ở múi giờ Europe/Istanbul:

departure_time_with_tz
2023-10-25 13:00:00+03

PostgreSQL sẽ tự động chuyển đổi thời gian từ UTC sang múi giờ bạn đã chọn.

Ví dụ thực tế

Xử lý múi giờ cho lịch trình. Giả sử bạn có bảng lịch trình chuyến bay, mỗi bản ghi lưu giờ khởi hành ở UTC. Bạn muốn hiển thị giờ khởi hành cho từng chuyến theo giờ địa phương.

SELECT
    flight_id,
    departure_time_with_tz AT TIME ZONE 'America/New_York' AS local_time
FROM flight_schedule;

So sánh dữ liệu thời gian từ các múi giờ khác nhau. Giả sử bạn so sánh hai sự kiện diễn ra ở hai thành phố khác nhau. PostgreSQL cho phép làm điều này, tự động chuyển dữ liệu về cùng một múi giờ.

SELECT
    '2023-10-25 10:00:00+03'::TIMESTAMPTZ > '2023-10-25 07:00:00+00'::TIMESTAMPTZ AS event_one_later;

Kết quả:

event_one_later
t

So sánh trả về true, vì 10:00+03 tương đương với 07:00+00.

Mẹo và những lỗi hay gặp

Làm việc với thời gian — đúng kiểu dễ dính bẫy. Đây là những lỗi hay gặp nhất:

  • Dùng TIMESTAMP thay vì TIMESTAMPTZ, rồi ngạc nhiên vì giờ không khớp — do múi giờ bị bỏ qua luôn.
  • Không biết server đang chạy ở múi giờ nào, nên dữ liệu thêm vào một giờ, đọc ra lại thành giờ khác.
  • Gõ sai tên múi giờ khi dùng AT TIME ZONE — và nhận lỗi hoặc ra giờ sai bét.

Để tránh bị troll:

  • Gần như luôn luôn dùng TIMESTAMPTZ, nhất là khi dữ liệu có thể phụ thuộc vào múi giờ.
  • Lưu thời gian ở UTC, còn khi hiển thị thì chuyển sang múi giờ user cần.
  • Nếu muốn tìm hiểu sâu hơn, đây là tài liệu chính thức PostgreSQL về thời gian và múi giờ — cực kỳ hữu ích luôn.
2
Nhiệm vụ
SQL SELF, mức độ, bài học
Đã khóa
Chuyển đổi UTC sang múi giờ New York
Chuyển đổi UTC sang múi giờ New York
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION