Thời gian hiện tại trong MySQL: NOW(), CURDATE(), UTC_TIMESTAMP(), Múi giờ và Các thực tiễn tốt nhất

目次

1. Lấy thời gian hiện tại trong MySQL (Kết luận: Bảng cheat sheet SQL ngắn nhất)

Nếu bạn muốn lấy thời gian hiện tại trong MySQL, chỉ có một vài hàm SQL bạn cần nhớ.
Dưới đây là câu trả lời ngắn nhất cho từ khóa tìm kiếm “MySQL get current time”.

1.1 Ngày và giờ hiện tại MySQL: NOW() / CURRENT_TIMESTAMP

Trả về ngày + giờ hiện tại (YYYY-MM-DD HH:MM:SS).

SELECT NOW();
SELECT CURRENT_TIMESTAMP;

Kết quả ví dụ

2025-02-01 15:30:45
  • NOW()CURRENT_TIMESTAMP thường trả về cùng một kết quả.
  • Cả hai đều trả về ngày và giờ hiện tại.
  • Nếu bạn cần mili giây, hãy sử dụng phần sau.
    SELECT NOW(3);
    

Ghi chú (những lỗi thường gặp)

  • Phụ thuộc vào cài đặt múi giờ của máy chủ.
  • Trong môi trường UTC, bạn có thể nhận được UTC thay vì giờ Nhật Bản.
  • Trong quá trình thực thi truy vấn, nó cơ bản trả về cùng một thời gian (cố định trong một câu lệnh).

1.2 Ngày hiện tại MySQL: CURDATE()

Chỉ trả về ngày (không có giờ).

SELECT CURDATE();

Kết quả ví dụ

2025-02-01

Trường hợp sử dụng

  • Truy vấn dữ liệu của hôm nay
  • So sánh ngày (ví dụ: lọc chỉ các bản ghi của hôm nay)

Ghi chú

  • Giá trị trả về là kiểu DATE.
  • Không phù hợp khi bạn cần xử lý thời gian trong ngày.

1.3 Thời gian hiện tại MySQL: CURTIME()

Chỉ trả về thời gian.

SELECT CURTIME();

Kết quả ví dụ

15:30:45

Trường hợp sử dụng

  • Kiểm tra giờ làm việc
  • Logic phân nhánh theo cửa sổ thời gian

Ghi chú

  • Không bao gồm thông tin ngày.
  • Không thể dùng để so sánh với các cột kiểu DATE.

1.4 Thời gian UTC hiện tại MySQL: UTC_TIMESTAMP()

Trả về thời gian theo UTC (Coordinated Universal Time), bất kể cài đặt múi giờ của máy chủ.

SELECT UTC_TIMESTAMP();

Kết quả ví dụ

2025-02-01 06:30:45

Khi nào nên sử dụng

  • Dịch vụ toàn cầu
  • Thiết kế lưu log theo UTC một cách nhất quán

Những lỗi thường gặp

  • Kết hợp với NOW() gây ra độ lệch thời gian
  • Nếu ứng dụng giả định JST, bạn sẽ thấy chênh lệch 9 giờ

1.5 Thời gian hiện tại MySQL với mili giây: NOW(3) / CURRENT_TIMESTAMP(3)

MySQL 5.6 trở lên hỗ trợ giây phân số.

SELECT NOW(3);
SELECT CURRENT_TIMESTAMP(3);

Kết quả ví dụ

2025-02-01 15:30:45.123

Ghi chú khi lưu trữ

Cột của bạn cũng phải hỗ trợ giây phân số.

DATETIME(3)
TIMESTAMP(3)

Nếu bạn lưu vào cột không hỗ trợ, phần phân số sẽ bị cắt bỏ.

1.6 Bảng cheat sheet nhanh theo mục đích

PurposeSQL
Current date and timeSELECT NOW();
Get UTCSELECT UTC_TIMESTAMP();
Date onlySELECT CURDATE();
Time onlySELECT CURTIME();
Get millisecondsSELECT NOW(3);

Tổng hợp các bẫy thường gặp

  • Thời gian bị lệch vì bạn không kiểm tra múi giờ
  • Sử dụng NOW(3) mà không có cột hỗ trợ mili giây
  • Kết hợp UTC và thời gian địa phương
  • Không hiểu sự khác biệt giữa DATETIME và TIMESTAMP

MySQL DATETIME と TIMESTAMP の違いを示した図。TIMESTAMPはUTC変換され、DATETIMEは変換されない。

Sự khác biệt giữa MySQL DATETIME và TIMESTAMP (so sánh việc có chuyển đổi múi giờ hay không)

2. Sự khác biệt giữa MySQL NOW() và CURRENT_TIMESTAMP

NOW()CURRENT_TIMESTAMP trông giống nhau, nhưng hiểu sai nơi sử dụng và cách chúng hoạt động có thể dễ dàng gây ra lỗi. Ở đây chúng tôi tổng hợp các khác biệt, cách sử dụng đúng, và những bẫy thường gặp.

2.1 Nên dùng cái nào? (sử dụng trong SELECT / sử dụng làm DEFAULT)

■ Khi lấy ngày/giờ hiện tại trong SELECT

SELECT NOW();
SELECT CURRENT_TIMESTAMP;

Thông thường, cả hai đều trả về cùng một kết quả.

  • Chúng tương đương (đồng nghĩa)
  • Giá trị trả về tương đương với DATETIME
  • Bị ảnh hưởng bởi cài đặt múi giờ

Bài học thực tiễn

  • Ưu tiên độ dễ đọc → NOW()
  • Ưu tiên phong cách chuẩn SQL → CURRENT_TIMESTAMP

■ Khi đặt giá trị mặc định cho cột

CREATE TABLE logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Điểm quan trọng ở đây là:

Đối với giá trị mặc định, thường dùng CURRENT_TIMESTAMP.

Một số môi trường cũng cho phép NOW(), nhưng hành vi có thể khác nhau tùy thuộc vào phiên bản MySQL và chế độ SQL. Lựa chọn an toàn hơn là CURRENT_TIMESTAMP.

2.2 Correct usage of DEFAULT / ON UPDATE

Nếu bạn muốn tự động cập nhật dấu thời gian “updated at”:

CREATE TABLE logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        ON UPDATE CURRENT_TIMESTAMP
);

Hành vi

  • Khi INSERT → đặt thời gian hiện tại cho created_at / updated_at
  • Khi UPDATE → chỉ cập nhật updated_at

Những lỗi thường gặp

  • Không khớp độ chính xác phần thập phân khi sử dụng DATETIME
  • Gặp phải các giới hạn của MySQL cũ khi có nhiều cột TIMESTAMP (MySQL 5.6 và các phiên bản trước có hạn chế)

2.3 Sự khác nhau giữa NOW() và SYSDATE() (Quan trọng)

Điểm dễ bỏ lỡ là sự khác biệt so với SYSDATE().

SELECT NOW(), SYSDATE();

■ Sự khác nhau về hành vi

  • NOW() → cố định tại thời điểm bắt đầu truy vấn
  • SYSDATE() → trả về thời gian tại thời điểm nó được gọi

Ví dụ:

SELECT NOW(), SLEEP(3), NOW();

NOW() trả về cùng một giá trị.

SELECT SYSDATE(), SLEEP(3), SYSDATE();

SYSDATE() cho thấy sự chênh lệch 3 giây.

2.4 Bạn nên dùng cái nào?

FunctionBehaviorRecommended use
NOW()Fixed within a queryLogging, consistency-focused
SYSDATE()Call-time valuePrecise real-time retrieval

Tại sao NOW() thường được khuyến nghị trong các hệ thống thực tế

  • Duy trì tính nhất quán trong một giao dịch (cơ chế xử lý nhiều câu lệnh SQL cùng nhau)
  • An toàn hơn trong môi trường sao chép

2.5 Những hiểu lầm và vấn đề thường gặp

❌ “NOW() và CURRENT_TIMESTAMP hoàn toàn giống nhau, vì vậy bạn không cần phải suy nghĩ về nó.”

→ Sự khác biệt có thể xuất hiện trong giá trị mặc định hoặc hành vi cập nhật, tùy thuộc vào môi trường.

❌ “SYSDATE() chính xác hơn, vì vậy nó luôn tốt hơn.”

→ Nó có thể gây ra vấn đề trong môi trường sao chép.

❌ Không kiểm tra múi giờ

SHOW VARIABLES LIKE '%time_zone%';

Nếu bạn sử dụng mà không kiểm tra, bạn có thể gặp sự chênh lệch thời gian.

2.6 Thực hành tốt nhất thực tế

  • Truy xuất SELECT → NOW()
  • Giá trị mặc định cột → CURRENT_TIMESTAMP
  • Tự động cập nhật → ON UPDATE CURRENT_TIMESTAMP
  • Tập trung vào tính nhất quán → mặc định là NOW()
  • Thiết kế dựa trên UTC → TIMESTAMP + lưu trữ ở UTC
  1. Định dạng Thời gian Hiện tại MySQL (DATE_FORMAT / TIME_FORMAT)
    Sau khi lấy thời gian hiện tại trong MySQL, việc thay đổi định dạng hiển thị là rất phổ biến.
    Đối với ý định tìm kiếm “MySQL current time format,” hàm quan trọng nhất cần hiểu là DATE_FORMAT().
    3.1 Định dạng datetime MySQL: DATE_FORMAT(NOW(), …)
    Cú pháp cơ bản:
    SELECT DATE_FORMAT(target_datetime, 'format_string');
    Ví dụ: định dạng thời gian hiện tại
    SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s');
    Kết quả ví dụ
    2025-02-01 15:30:45
    Các chỉ định định dạng thường dùng
    Chỉ định
    Ý nghĩa
    Ví dụ
    %Y
    Năm (4 chữ số)
    2025
    %m
    Tháng (2 chữ số)
    02
    %d
    Ngày (2 chữ số)
    01
    %H
    Giờ (24-giờ)
    15
    %h
    Giờ (12-giờ)
    03
    %i
    Phút
    30
    %s
    Giây
    45
    %p
    AM/PM
    PM
    3.2 Chuyển đổi sang định dạng kiểu Nhật Bản hoặc 12-giờ
    ■ Định dạng kiểu Nhật Bản
    SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i');
    Kết quả ví dụ:
    2025-02-01 15:30
    ■ Định dạng 12-giờ + AM/PM
    SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %h:%i:%s %p');
    Kết quả ví dụ:
    2025-02-01 03:30:45 PM
    3.3 Định dạng chỉ thời gian MySQL: TIME_FORMAT()
    Hàm định dạng dành riêng cho dữ liệu kiểu TIME.
    SELECT TIME_FORMAT(CURTIME(), '%H:%i');
    Kết quả ví dụ:
    15:30
    Ghi chú
    TIME_FORMAT() chỉ dành cho kiểu TIME
    Đối với DATETIME, sử dụng DATE_FORMAT()
    3.4 Chuyển đổi chuỗi → datetime: STR_TO_DATE()
    Để chuyển đổi dữ liệu chuỗi thành kiểu datetime:
    SELECT STR_TO_DATE('2025-02-01 15:30:45', '%Y-%m-%d %H:%i:%s');
    Kết quả ví dụ:
    2025-02-01 15:30:45
    Lỗi phổ biến
    Sự không khớp định dạng sẽ trả về NULL
    Nhầm lẫn giữa %m%c (tháng có đệm số 0 so với không đệm số 0)
    3.5 Các điểm quan trọng trong sản xuất
    ❌ Không so sánh sau khi định dạng
    Ví dụ xấu:
    WHERE DATE_FORMAT(created_at, '%Y-%m-%d') = '2025-02-01';
    Điều này không được khuyến nghị vì chỉ mục trở nên không hiệu quả (hiệu suất truy vấn giảm sút).
    Khuyến nghị:
    WHERE created_at >= '2025-02-01' AND created_at < '2025-02-02';
    ❌ Đừng định dạng quá mức ở phía cơ sở dữ liệu
    Trong ứng dụng web, việc định dạng để hiển thị thường linh hoạt hơn ở phía ứng dụng
    Cơ sở dữ liệu nên tập trung vào “lưu trữ và tính toán”
    3.6 Định dạng với mili giây
    SELECT DATE_FORMAT(NOW(3), '%Y-%m-%d %H:%i:%s.%f');
    %f đại diện cho micro giây (6 chữ số).
    Ghi chú
    Nếu cột không phải là DATETIME(3) hoặc tương tự, phần thập phân sẽ bị cắt bỏ
    Có sẵn trong MySQL 5.6 và các phiên bản sau
    3.7 Tóm tắt theo mục đích định dạng
    Mục đích
    Hàm
    Thay đổi định dạng hiển thị
    DATE_FORMAT
    Định dạng chỉ thời gian
    TIME_FORMAT
    Chuyển đổi chuỗi → datetime
    STR_TO_DATE
    Hiển thị mili giây
    %f
  2. Cộng/Trừ Ngày Giờ MySQL (DATE_ADD / DATE_SUB)
    Ngay cả khi bạn có thể lấy thời gian hiện tại, bạn không thể sử dụng nó hiệu quả trong sản xuất mà không có các phép tính ngày/giờ như “X ngày sau” hoặc “X giờ trước.”
    Ở đây chúng tôi giải thích cách sử dụng DATE_ADD()DATE_SUB() với thời gian hiện tại trong MySQL.
    4.1 Cộng datetime MySQL: DATE_ADD()
    Cú pháp cơ bản:
    SELECT DATE_ADD(base_datetime, INTERVAL value unit);
    Ví dụ: 7 ngày từ bây giờ
    SELECT DATE_ADD(NOW(), INTERVAL 7 DAY);
    Ví dụ: 2 giờ sau
    SELECT DATE_ADD(NOW(), INTERVAL 2 HOUR);
    Các đơn vị thường dùng
    Đơn vị
    Ý nghĩa
    SECOND
    Giây
    MINUTE
    Phút
    HOUR
    Giờ
    DAY
    Ngày
    MONTH
    Tháng
    YEAR
    Năm
    4.2 Trừ datetime MySQL: DATE_SUB()
    Cú pháp cơ bản:
    SELECT DATE_SUB(base_datetime, INTERVAL value unit);
    Ví dụ: 30 ngày trước
    SELECT DATE_SUB(NOW(), INTERVAL 30 DAY);
    Ví dụ: 1 giờ trước
    SELECT DATE_SUB(NOW(), INTERVAL 1 HOUR);
    Trường hợp sử dụng
    Kiểm tra hết hạn
    Xóa nhật ký cũ
    Trích xuất dữ liệu gần đây
    4.3 Các mẫu sản xuất phổ biến
    ■ Lấy dữ liệu từ 24 giờ trước
    SELECT * FROM logs WHERE created_at >= DATE_SUB(NOW(), INTERVAL 1 DAY);
    ■ Đặt thời hạn 7 ngày sau
    INSERT INTO tasks (deadline) VALUES (DATE_ADD(NOW(), INTERVAL 7 DAY));

4.4 Những lỗi thường gặp và lưu ý
❌ Áp dụng hàm lên cột
Ví dụ sai:
WHERE DATE(created_at) = CURDATE();
Điều này vô hiệu hoá chỉ mục (tối ưu hoá hiệu suất truy vấn).
Khuyến nghị:
WHERE created_at >= CURDATE() AND created_at < DATE_ADD(CURDATE(), INTERVAL 1 DAY);
❌ Bỏ qua múi giờ
NOW() dựa trên múi giờ của máy chủ
Nếu bạn lưu ở UTC, hãy dùng UTC_TIMESTAMP() làm cơ sở
Ví dụ:
SELECT DATE_ADD(UTC_TIMESTAMP(), INTERVAL 1 DAY);
❌ Cạm bẫy khi cộng tháng
SELECT DATE_ADD('2025-01-31', INTERVAL 1 MONTH);
→ Do điều chỉnh cuối tháng, ngày có thể thay đổi.
(Kết quả có thể là 2025-02-28 tùy thuộc vào môi trường.)
Hiểu rõ đặc tả trước khi sử dụng các phép tính dựa trên tháng.
4.5 Cộng với mili giây
SELECT DATE_ADD(NOW(3), INTERVAL 500 MILLISECOND);
※ MySQL không hỗ trợ MILLISECOND trực tiếp.
Có thể chỉ định bằng micro giây:
SELECT DATE_ADD(NOW(3), INTERVAL 500000 MICROSECOND);
4.6 Thực hành tốt
Chuẩn hoá việc dùng NOW() hoặc UTC_TIMESTAMP() làm cơ sở
Không áp dụng hàm lên cột trong mệnh đề WHERE
Hiểu hành vi của phép cộng dựa trên tháng
Nếu cần độ chính xác, sử dụng DATETIME(3) hoặc cao hơn

5. Tính toán chênh lệch ngày/giờ trong MySQL (DATEDIFF / TIMESTAMPDIFF)

Trong các hệ thống sản xuất, chỉ lấy thời gian hiện tại là không đủ.
Bạn thường cần tính số ngày đã trôi qua hoặc số giờ còn lại.

5.1 Tính chênh lệch ngày: DATEDIFF()

DATEDIFF() tính chênh lệch số ngày giữa hai ngày.

SELECT DATEDIFF('2025-02-10', '2025-02-01');

Kết quả

9

Các điểm chính

  • Trả về chênh lệch chỉ tính ngày
  • Phần thời gian bị bỏ qua
  • Kết quả có thể là số âm

Ví dụ: tính số ngày kể từ khi tạo

SELECT DATEDIFF(NOW(), created_at)
FROM users;

5.2 Tính chênh lệch theo đơn vị: TIMESTAMPDIFF()

TIMESTAMPDIFF() cho phép bạn chỉ định đơn vị.

SELECT TIMESTAMPDIFF(unit, start_datetime, end_datetime);

Ví dụ: chênh lệch giờ

SELECT TIMESTAMPDIFF(HOUR, '2025-02-01 10:00:00', '2025-02-01 15:00:00');

Kết quả

5

Các đơn vị thường dùng

UnitMeaning
SECONDSeconds
MINUTEMinutes
HOURHours
DAYDays
MONTHMonths
YEARYears

Ví dụ: tính số phút kể từ khi đăng nhập

SELECT TIMESTAMPDIFF(MINUTE, login_at, NOW())
FROM users;

5.3 Các trường hợp sử dụng trong sản xuất

  • Kiểm tra thời gian hết phiên
  • Kiểm tra ngày hết hạn thuê bao
  • Tính thời gian đã trôi qua trong log
  • Logic giới hạn tần suất

5.4 Những lỗi thường gặp

❌ Sử dụng DATEDIFF khi cần độ chính xác thời gian

DATEDIFF() bỏ qua giờ và phút.

❌ Đảo ngược thứ tự đối số

Thứ tự là:

TIMESTAMPDIFF(unit, start, end)

Nếu đảo ngược, kết quả sẽ là số âm.

❌ Bỏ qua múi giờ

Nếu trộn UTC và thời gian địa phương, chênh lệch có thể sai.

5.5 Thực hành tốt

  • Sử dụng TIMESTAMPDIFF() khi độ chính xác thời gian quan trọng
  • Sử dụng DATEDIFF() cho các phép tính ngày đơn giản
  • Đảm bảo sử dụng đồng nhất múi giờ
  • Chuẩn hoá việc dùng UTC trong các hệ thống phân tán

6. Truy vấn phạm vi ngày bằng thời gian hiện tại

Một trong những yêu cầu thực tế phổ biến nhất là truy xuất bản ghi trong một khoảng thời gian cụ thể, chẳng hạn:

  • Bản ghi của hôm nay
  • 7 ngày qua
  • 24 giờ qua
  • Tháng hiện tại

6.1 Truy xuất bản ghi của hôm nay (thân thiện với chỉ mục)

SELECT *
FROM logs
WHERE created_at >= CURDATE()
  AND created_at < DATE_ADD(CURDATE(), INTERVAL 1 DAY);

Tại sao cách này đúng

  • Không áp dụng hàm lên cột
  • Các chỉ mục vẫn có thể sử dụng
  • Truy vấn phạm vi hiệu quả

6.2 7 ngày qua

SELECT *
FROM logs
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY);

6.3 24 giờ qua

SELECT *
FROM logs
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 1 DAY);

6.4 Tháng hiện tại

SELECT *
FROM logs
WHERE created_at >= DATE_FORMAT(NOW(), '%Y-%m-01')
  AND created_at < DATE_ADD(DATE_FORMAT(NOW(), '%Y-%m-01'), INTERVAL 1 MONTH);

Trong các hệ thống sản xuất, thường tốt hơn khi tính toán các ranh giới ở phía ứng dụng và truyền chúng như các tham số.

6.5 Các lỗi hiệu năng phổ biến

❌ Áp dụng hàm lên các cột đã được lập chỉ mục

WHERE DATE(created_at) = CURDATE();

Điều này ngăn việc sử dụng chỉ mục và gây ra việc quét toàn bộ bảng.

❌ Sử dụng BETWEEN một cách cẩu thả

BETWEEN bao gồm cả hai đầu và có thể gây ra các vấn đề lệch một giây.

6.6 Tóm tắt các thực tiễn tốt nhất

  • Luôn sử dụng các điều kiện phạm vi cho việc lọc ngày
  • Tránh áp dụng hàm lên các cột đã được lập chỉ mục
  • Ưu tiên lưu trữ theo UTC trong các hệ thống toàn cầu
  • Rõ ràng về các giả định múi giờ