Những nguyên lý quan trọng về ngày, tháng, năm trong lập trình dành cho người mới bắt đầu

Xử lý ngày tháng năm là một nhóm bài toán xuất hiện dày đặc trong lập trình: kiểm tra năm nhuận, tìm số ngày trong tháng, xác định ngày hợp lệ, tính tuổi, tính ngày tiếp theo–ngày trước đó… Đây là các dạng bài “gần như chắc chắn gặp” khi học nhập môn. Bài viết này tổng hợp toàn bộ nguyên lý nền tảng mà lập trình viên cần nắm, kèm ví dụ chuẩn và giải thích đầy đủ.

Những nguyên lý quan trọng về ngày, tháng, năm trong lập trình dành cho người mới bắt đầu

1. Hiểu nền tảng: lịch Gregorian

Hầu hết ngôn ngữ lập trình ngày nay (JavaScript, Java, C++, Python…) sử dụng lịch Gregorian – hệ lịch hiện hành trên toàn thế giới. Do đó, khi xử lý ngày tháng, mặc định bạn đang làm việc với lịch này.

Đặc điểm chính:

  • Năm có 365 ngày (bình thường) hoặc 366 ngày (năm nhuận).
  • Chu kỳ nhuận được thiết kế để khớp với chu kỳ quay của Trái Đất quanh Mặt Trời (~365.2425 ngày).
  • Có 12 tháng, mỗi tháng số ngày cố định (trừ tháng 2 phụ thuộc năm nhuận).

2. Quy tắc năm nhuận (cực kỳ quan trọng)

Đây là kiến thức cốt lõi mà hầu hết bài tập đều dùng.

Một năm được xem là năm nhuận nếu thỏa một trong các điều kiện sau (theo thứ tự ưu tiên):

  • Năm chia hết cho 400 ⇒ Năm nhuận.
  • Nếu không chia hết cho 400 nhưng chia hết cho 100 ⇒ Không nhuận.
  • Nếu chia hết cho 4 ⇒ Năm nhuận.
  • Còn lại ⇒ Không nhuận.

Code mẫu:

function isLeapYear(year) {
  if (year % 400 === 0) return true;
  if (year % 100 === 0) return false;
  if (year % 4 === 0) return true;
  return false;
}

Lỗi người mới thường gặp:

  • Tưởng “chia hết cho 4” là đủ ⇒ sai.
  • Bỏ qua trường hợp “chia hết cho 100 nhưng không nhuận”.
  • Không biết rằng 2000 là nhuận nhưng 1900 lại không.

3. Số ngày của từng tháng

Bảng số ngày chuẩn:

  • Tháng 1, 3, 5, 7, 8, 10, 12 ⇒ 31 ngày.
  • Tháng 4, 6, 9, 11 ⇒ 30 ngày.
  • Tháng 2:
    • Năm nhuận ⇒ 29 ngày
    • Năm không nhuận ⇒ 28 ngày

Hàm tính số ngày trong tháng:

function getDaysInMonth(month, year) {
  if (month === 2) return isLeapYear(year) ? 29 : 28;
  const months31 = [1, 3, 5, 7, 8, 10, 12];
  return months31.includes(month) ? 31 : 30;
}

4. Kiểm tra ngày hợp lệ

Đây là bài kinh điển: nhập ngày/tháng/năm, kiểm tra ngày đó có tồn tại không.

Điều kiện hợp lệ:

  1. Năm > 0.
  2. 1 ≤ tháng ≤ 12.
  3. 1 ≤ ngày ≤ số ngày trong tháng đó.

Hàm chuẩn:

function isValidDate(day, month, year) {
  if (year <= 0) return false;
  if (month < 1 || month > 12) return false;
  const maxDay = getDaysInMonth(month, year);
  return day >= 1 && day <= maxDay;
}

Lỗi hay gặp:

  • Không kiểm tra tháng trước khi lấy số ngày ⇒ crash logic.
  • Coi 31/04 là hợp lệ (nhưng tháng 4 chỉ có 30 ngày).
  • Không xét năm nhuận ⇒ 29/02 báo sai.

5. Tính tuổi từ ngày sinh

Dạng bài này yêu cầu hiểu rõ rằng tuổi phụ thuộc vào việc đã qua sinh nhật hay chưa.

function calculateAge(day, month, year) {
  const now = new Date();
  let age = now.getFullYear() - year;

  if (
    now.getMonth() + 1 < month ||
    (now.getMonth() + 1 === month && now.getDate() < day)
  ) {
    age--;
  }

  return age;
}

Điểm cần lưu ý:

  • Không được lấy tuổi = currentYear – birthYear đơn thuần.
  • Luôn kiểm tra xem đã tới sinh nhật năm nay chưa.

6. Tính ngày kế tiếp (Next Day)

Bài này giúp bạn hiểu mối quan hệ giữa ngày – tháng – năm.

Nguyên lý:

  1. Tăng ngày lên 1.
  2. Nếu vượt quá số ngày trong tháng ⇒ reset về 1 và tăng tháng.
  3. Nếu tháng vượt 12 ⇒ reset về 1 và tăng năm.

Code chuẩn:

function nextDay(day, month, year) {
  day++;
  const maxDay = getDaysInMonth(month, year);

  if (day > maxDay) {
    day = 1;
    month++;
    if (month > 12) {
      month = 1;
      year++;
    }
  }

  return { day, month, year };
}

7. Tính ngày trước đó (Previous Day)

Nguyên lý:

  1. Giảm ngày đi 1.
  2. Nếu day = 0 ⇒ lùi lại tháng trước & lấy số ngày của tháng trước.
  3. Nếu tháng 0 ⇒ lùi về tháng 12 của năm trước.
function previousDay(day, month, year) {
  day--;

  if (day === 0) {
    month--;
    if (month === 0) {
      month = 12;
      year--;
    }
    day = getDaysInMonth(month, year);
  }

  return { day, month, year };
}

8. Khoảng cách giữa hai ngày (Day Difference)

Bài nâng cao: tính số ngày giữa 2 mốc thời gian.

Công thức đơn giản nhất:

const d1 = new Date(year1, month1 - 1, day1);
const d2 = new Date(year2, month2 - 1, day2);
const diff = Math.abs(d2 - d1) / (1000 * 60 * 60 * 24);

Lưu ý:

  • JavaScript đếm tháng từ 0 đến 11.
  • Chuyển về milliseconds rồi chia ngược để ra số ngày.

9. Các lỗi kinh điển cần tránh

  • Nhầm tháng đếm từ 0 ⇒ chỉ riêng JS mới vậy.
  • Không kiểm tra input trước khi tính ⇒ gây kết quả sai hoặc NaN.
  • Dùng sai định dạng ngày (ví dụ 31/02 nhưng không kiểm tra).
  • Bỏ qua tính sinh nhật khi tính tuổi.
  • Không bao quát năm nhuận trong các bài next day / previous day.

10. Bài tập gợi ý để luyện sâu

  • Kiểm tra ngày mai của một ngày bất kỳ.
  • Viết hàm trả về ngày thứ mấy trong tuần, không dùng Date().
  • Tính số ngày còn lại đến cuối năm.
  • Tính số ngày đã trôi qua từ đầu năm đến ngày bất kỳ.
  • Tính khoảng cách giữa 2 ngày (thuật toán thủ công, không dùng Date).

Chỉ cần nắm chắc các nguyên lý trong bài viết, bạn có thể xử lý toàn bộ nhóm bài ngày tháng năm từ cơ bản đến nâng cao một cách tự tin và chính xác.

Bình luận


  • Không có bình luận.

Init Toolbox

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...