DHDataHọc
TheoryLesson 28/304 min read+10 XP

Ngày và giờ

Bạn sẽ học được

  • date, datetime, timedelta và khi nào dùng cái nào.
  • Cộng trừ thời gian, tính khoảng cách giữa hai mốc.
  • Chuyển chuỗi → ngày và ngày → chuỗi với strptime / strftime.
  • Múi giờ: naive, aware, UTC và giờ Việt Nam.
  • Các lỗi thời gian thường gặp trong dữ liệu thật.

Khái niệm cốt lõi

Module datetime có ba kiểu chính:

KiểuBiểu diễnDùng khi
dateNgày, không giờNgày sinh, ngày giao dịch
datetimeNgày + giờThời điểm log, tạo đơn
timedeltaKhoảng thời gianCộng trừ, tính chênh lệch
code
from datetime import date, timedelta

d = date(2026, 1, 31)
print(d + timedelta(days=1))
print(d - timedelta(days=30))
code
2026-02-01
2026-01-01

Python tự xử lý số ngày trong tháng, năm nhuận, chuyển tháng — không cần tự tính. timedelta nhận days, hours, minutes, seconds, weeks.

Trừ hai ngày cho timedelta:

code
print(date(2026, 3, 1) - date(2026, 1, 1))
code
59 days, 0:00:00

Năm 2026 không nhuận, nên tháng 1 có 31 ngày, tháng 2 có 28: 31 + 28 = 59. Muốn lấy số ngày nguyên, dùng .days:

code
delta = date(2026, 3, 1) - date(2026, 1, 1)
print(delta.days)

Chuỗi ↔ ngày

strptime (parse) chuyển chuỗi thành datetime theo định dạng; strftime (format) làm ngược lại:

code
from datetime import datetime

dt = datetime.strptime("2026-01-05 14:30", "%Y-%m-%d %H:%M")
print(dt.year, dt.month, dt.day, dt.hour, dt.minute)
print(dt.strftime("%d/%m/%Y %H:%M"))
code
2026 1 5 14 30
05/01/2026 14:30

Các mã định dạng hay dùng:

MãÝ nghĩaVí dụ
%YNăm 4 chữ số2026
%mTháng 2 chữ số01
%dNgày 2 chữ số05
%HGiờ 24h14
%MPhút30
%SGiây00
%Y-%m-%dISO date2026-01-05

strptime rất khắt khe: chuỗi không khớp định dạng sẽ ném ValueError. Đây là lý do khi đọc ngày từ CSV, cần biết chính xác định dạng nguồn. Với dữ liệu có nhiều định dạng, thử lần lượt và bắt lỗi:

code
def doc_ngay(raw):
    for fmt in ("%Y-%m-%d", "%d/%m/%Y"):
        try:
            return datetime.strptime(raw, fmt).date()
        except ValueError:
            continue
    return None

print(doc_ngay("2026-01-05"), doc_ngay("05/01/2026"), doc_ngay("01/05/26"))
code
2026-01-05 2026-01-05 None

Cẩn thận với 05/01/2026: theo định dạng %d/%m/%Y là 5 tháng 1; nếu dữ liệu Mỹ dùng %m/%d/%Y thì thành 1 tháng 5. Luôn xác nhận quy ước của nguồn.

Múi giờ

datetime không có tzinfo là naive — không biết múi giờ. Có tzinfo là aware. So sánh hoặc trừ naive với aware sẽ ném TypeError.

code
from datetime import timezone, timedelta

utc = datetime(2026, 1, 5, 14, 30, tzinfo=timezone.utc)
vn = timezone(timedelta(hours=7))
print(utc.astimezone(vn).isoformat())
code
2026-01-05T21:30:00+07:00

Cùng một thời điểm, biểu diễn theo giờ Việt Nam là 21:30. Quy tắc thực dụng:

  • Lưu trữ và trao đổi: UTC (aware hoặc chuỗi ISO có offset).
  • Hiển thị: chuyển sang múi giờ người dùng.
  • Tính toán: dùng aware để tránh nhầm.

Lấy thời điểm hiện tại:

code
from datetime import datetime, timezone

now_utc = datetime.now(timezone.utc)
today = date.today()

Không dùng datetime.now() trần cho dữ liệu sẽ lưu trữ — nó phụ thuộc múi giờ máy chạy và không có offset.

Làm việc với ngày trong dữ liệu

Mẫu phổ biến: nhóm doanh thu theo tháng. Chuỗi ISO "2026-01-05" có thể cắt 7 ký tự đầu, nhưng cách chắc chắn hơn là parse rồi format:

code
raw = "2026-01-05"
d = datetime.strptime(raw, "%Y-%m-%d").date()
print(d.strftime("%Y-%m"))
code
2026-01

Với dữ liệu lớn, parse một lần khi đọc và giữ kiểu date/datetime trong bộ nhớ, thay vì parse lại mỗi lần dùng.

Thực hành

  1. Cộng 1 ngày vào 2026-01-31 và kiểm tra chuyển tháng.
  2. Trừ 30 ngày, in kết quả.
  3. Tính số ngày giữa 2026-01-01 và 2026-03-01.
  4. Parse "2026-01-05 14:30" và format lại thành 05/01/2026 14:30.
  5. Viết hàm đọc ngày theo hai định dạng, trả None nếu không khớp.
  6. Chuyển 14:30 UTC sang giờ Việt Nam và in ISO có offset.

Lỗi thường gặp

Triệu chứngNguyên nhânCách sửa
ValueError khi parseChuỗi khớp sai định dạngKiểm tra %d/%m, thử nhiều format
TypeError: can't subtract offset-naive and offset-awareTrộn naive với awareChuẩn hoá về UTC aware
Giờ lệch 7 tiếngLưu giờ địa phương không offsetLưu UTC, hiển thị theo múi giờ
Ngày đảo tháng/ngàyNhầm %d/%m với %m/%dXác nhận quy ước nguồn
strftime in saiMã định dạng saiĐối chiếu bảng mã
timedelta hiện 59 days, 0:00:00Chưa lấy .daysDùng .days
So sánh ngày lỗiMột bên là chuỗiParse trước khi so sánh

Tóm tắt

  • date cho ngày, datetime cho thời điểm, timedelta cho khoảng.
  • Cộng trừ tự xử lý tháng, năm nhuận.
  • strptime chuỗi → ngày; strftime ngày → chuỗi; sai format là ValueError.
  • Lưu UTC, hiển thị theo múi giờ; không trộn naive với aware.
  • Parse ngày ngay khi đọc dữ liệu, đừng so sánh chuỗi ngày.

Use ← → to move between lessons