Bàn về bài toán “Xác định thứ trong tuần dựa trên ngày - tháng – năm”
Bạn có thể xem bài này trên blog của tôi tại
- Code:
-
http://vn.360plus.yahoo.com/levientrinh-DH10TH
Đã có bao giờ bạn muốn biết một ngày nào đó là ngày thứ mấy trong tuần. Nếu như ngày đó là ngày mà bạn có thể tra cứu được trên lịch thì chẳng có gì đáng phải bàn, tuy nhiên nếu đó là một ngày ở trong quá khứ thì sao (chẳng hạn như ngày sinh của mình, sự kiện đặc biệt nào đó trong quá khứ,…). Chúng ta sẽ bàn về cách để xác định đó là ngày thứ mấy trong tuần mà không cần phải dùng lịch hoặc không thể xác định chỉ qua một vài phép tính đơn giản. Thực sự ra mà nói nếu bạn đã từng sử dụng ứng dụng văn phòng Microsoft Excel thì nó có hỗ trợ cho chúng ta một hàm tên là WEEKDAY() với đối số đầu vào là ngày tháng năm dùng để xác định đó là ngày thứ mấy trong tuần. Nhưng chúng ta sẽ giải bài toán này thông qua một giải thuật rất đơn giản sau đây.
Đầu tiên, bạn phải tính được giá trị của biểu thức như sau
S = Year - 1 + ((Year - 1) / 4) - ((Year - 1) / 100) + ((Year - 1) / 400) + khoangNgay;
Trong đó Year là số năm. khoangNgay là số ngày từ đầu năm đến ngày mà ta cần tìm. Kết quả của các phép tính chia trong biểu thức trên đều lấy phần nguyên. Bạn cứ yên tâm là ta sẽ không phải cần chuyển đổi kiểu của phép tính này bởi vì trong cơ chế thực hiện phép chia của C# thì nếu tử và mẫu đều là số nguyên thì kết quả sẽ trả về phần nguyên. Trong trường hợp tử hoặc mẫu là số thực thì kết quả sẽ trả về số thực. Do đó trong khi tính toán bạn chỉ cần cho biến Year có kiểu nguyên là được.
Để tính được giá trị khoangNgay thì bạn hãy xem ví dụ sau :
Tôi cần xác định thứ là ngày 01/3/2011. Ta sẽ tính giá trị khoangNgay sẽ là = 31 + 28 + 1 = 60. Trong đó 31 là số ngày của tháng 1, 28 là số ngày của tháng 2, 1 là ngày mà ta cần tính xác định thứ. Đối với một số năm thì tháng 2 có thể có 29 ngày. Do đó để xác định số ngày của một tháng trong một năm nào đó mà không cần phải thao tác nhiều ta có thể sử hàm DaysInMonth(int year, int month) của lớp DateTime.
Sau khi tính được giá trị S ở trên bạn tiến hành lấy phần dư của phép chia S cho 7. Kết quả phần dư của phép chia này chính là thứ trong tuần của ngày ta tiến hành xác định. Nếu phần dư là 0, thì đó là ngày Chủ Nhật, nếu phần dư là 1 đó là ngày thứ Hai, nếu phần dư là 2 đó là ngày thứ Ba,… nếu phần dư là 6 đó là ngày thứ Bảy.
Bây giờ để minh họa cho giải thuật này tôi sẽ minh họa một Form trong C# có giao diện cơ bản như sau (nếu bạn học lớp DH10TH – Đại học An Giang và đang học môn học lập trình trên Windows thì bạn có thể xem bài tập số 1 - phần III - xử lý các điều khiển - bài tập Visual Basic cơ bản).
Mô tả :
- cbxYear là một Combobox chứa năm. Bạn dùng thuộc tính MinValue và MaxValue của lớp DateTime để nạp số năm vào Combobox này.
- cbxMonth là một Combobox chứa tháng.
- cbxDay là một Combobox chứa ngày. Ngày này bạn nên dùng hàm DaysInMonth nói ở trên để nạp các ngày vào Combobox này.
- btnDocNgay dùng để tính và xuất kết quả lên txtKetQua và btnThoat dùng để thoát khỏi chương trình.
Để cho chương trình chạy đúng, bạn nên chọn năm, sau đó chọn tháng, cuối cùng chọn ngày.
Tham khảo đoạn Code sau đây (dựa trên giải thuật được trình bày ở trên). Tải source code tại
[You must be registered and logged in to see this link.] (viết trên Visual Studio 2010), đối với phiên bản thấp hơn, bạn có thể tự tay viết lại chương trình hoặc chép đoạn code vào dự án của mình.
- Code:
-
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Doc_ngay
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnThoat_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Bạn có muốn thoát khỏi ứng dụng không ?", "Exit", MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
{
Application.Exit();
}
}
private void Form1_Load(object sender, EventArgs e)
{
for (int i = DateTime.MinValue.Year; i <= DateTime.MaxValue.Year; i++)
{
cbxYear.Items.Add(i);
}
}
private void cbxYear_SelectedIndexChanged(object sender, EventArgs e)
{
btnDocNgay.Enabled = true;
for (int i = 1; i <= 12; i++)
{
cbxMonth.Items.Add(i);
}
}
private void cbxMonth_SelectedIndexChanged(object sender, EventArgs e)
{
btnDocNgay.Enabled = true;
int ngay = DateTime.DaysInMonth(Convert.ToInt32(cbxYear.Text), Convert.ToInt32(cbxMonth.Text));
for (int i = 1; i <= ngay; i++)
{
cbxDay.Items.Add(i);
}
}
private void btnDocNgay_Click(object sender, EventArgs e)
{
btnDocNgay.Enabled = false;
int Year = Convert.ToInt32(cbxYear.Text);
int Month = Convert.ToInt32(cbxMonth.Text);
int Day = Convert.ToInt32(cbxDay.Text);
int khoangNgay = Day;
for (int i = 1; i <= Month - 1; i++)
{
khoangNgay += DateTime.DaysInMonth(Year, i);
}
int S = Year - 1 + ((Year - 1) / 4) - ((Year - 1) / 100) + ((Year - 1) / 400) + khoangNgay;
string thuMay = null;
switch (S % 7)
{
case 0: thuMay = "Chủ Nhật";
break;
case 1: thuMay = "Thứ Hai";
break;
case 2: thuMay = "Thứ Ba";
break;
case 3: thuMay = "Thứ Tư";
break;
case 4: thuMay = "Thứ Năm";
break;
case 5: thuMay = "Thứ Sáu";
break;
case 6: thuMay = "Thứ Bảy";
break;
}
txtKetQua.Text = thuMay + " " + Day + "/" + Month + "/" + Year;
}
private void cbxDay_SelectedIndexChanged(object sender, EventArgs e)
{
btnDocNgay.Enabled = true;
}
}
}
Sau khi chạy chương trình này, giả sử hôm nay tôi chọn năm là 2011, tháng là 9, ngày là 7. Kết quả sẽ hiện như sau :
Trong C# có hỗ trợ cho bạn sử dụng một hàm trong lớp DateTime để xác định thứ của một ngày. Xem code sau :
- Code:
-
DateTime dt = new DateTime(2011, 9, 7);
Console.WriteLine(dt.DayOfWeek.ToString());
Bạn có thể xem thêm giải thuật xác định thứ dựa trên một ngày tại Wikipedia English (http://en.wikipedia.org/wiki/Calculating_the_day_of_the_week).
Chúc các bạn thành công !