30/09/2018, 23:13

Cần source code về tạo lịch ngày tháng năm

Mình cần cái ý tưởng, thủ thuật để xây dưng lịch trên android ạ, đang tập tành. Hi vọng mọi người có thể chia sẻ java, c, c# gì cũng đc ạ

Khoa Nguyen viết 01:21 ngày 01/10/2018

Một bài viết hay (JS) bạn có thể tham khảo http://kipalog.com/posts/Phuc-tap-hoa-van-de--Datepicker-va-cac-thuat-toan-dang-sau-no

viết 01:29 ngày 01/10/2018

cái này chung guy gộp về bài toán tìm ngày đầu tiên trong tháng là ngày thứ mấy, mình cũng có tự chế ra 1 hàm để làm điều này:

const std::string DAY_OF_WEEK[] = { //for clarification purpose
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

int getDayOfWeek(int y, int m, int d)
{
    static const int wdMGap[] = { 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 };
    int wd = y - 1901;   //year starts from 1901
    wd += wd/4;          //add leap years
    wd += wdMGap[m-1];   //add the corresponding month gap
    wd += m>2 && y%4==0; //account for months > 2 in leap year
    wd += d;             //add days
    return (wd+1) % 7;   //+1 to match week day of 1901/1/1
}

có điều nó chỉ đúng được cho những năm trong đoạn [1901,2099]. Cái leap year trick vãi ra Vì cái leap year làm xấu code nên mình bỏ nó luôn, cho năm trong đoạn [1901,2099] thì chỉ cần lấy y%4 là ra năm nhuận rồi.

viết 01:27 ngày 01/10/2018

để mò ra được hàm này thì ta bắt đầu với ngày đầu tiên trong năm là ngày thứ mấy:
test cases là

const std::string DAY_OF_WEEK[] = { //for clarification purpose
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

// Test cases for first day of year
{1901, 1, 1, 2},
{1902, 1, 1, 3},
{1903, 1, 1, 4},
{1904, 1, 1, 5},
{1905, 1, 1, 0},
{2000, 1, 1, 6},
{2015, 1, 1, 4}

nghĩa là ngày 1/1/1901 là ngày thứ ba, 1/1/1902 là thứ 4, v.v… Ta nhận thấy với năm 1901, 1902, 1903, 1904 thì chỉ cần return ((y-1901)+2) % 7; là ra. Nhưng tới 1905 thì có ngoại lệ: thay vì cộng 1 ngày, ta cần cộng 2 ngày (vì 1904 là năm nhuận), hay tổng quát hóa là ta cần cộng số năm nhuận tính từ năm 1901. Vậy sửa code thành:

int wd = y - 1901;   //year starts from 1901
wd += wd / 4;        //add leap years
return (wd + 2) % 7; //+2 to match with 1901/1/1

thử với 2015: 2015 - 1901 = 114.
114 + 114/4 = 114 + 28 = 142.
142 + 2 = 144.
144 % 7 = 4 => pass test
công thức tính năm nhuận được đơn giản hóa chỉ còn y%4 nên mới phải giới hạn trong 200 năm 1901-2099

tiếp theo là tìm ngày đầu tiên trong tháng là ngày thứ mấy:
ta bắt đầu với 12 test case trong năm ko nhuận, vd 2015 đi:

// Test cases for first day of month, non-leap year
{2015, 1, 1, 4},
{2015, 2, 1, 0},
{2015, 3, 1, 0},
{2015, 4, 1, 3},
{2015, 5, 1, 5},
{2015, 6, 1, 1},
{2015, 7, 1, 3},
{2015, 8, 1, 6},
{2015, 9, 1, 2},
{2015, 10, 1, 4}
{2015, 11, 1, 0}
{2015, 12, 1, 2}

cái này nếu có số ngày trong tháng thì cũng ra dễ thôi, nhưng thay vì làm vậy, chúng ta chỉ cần nhìn vào bảng test mà suy luận thì cũng ra: vì chúng ta đã biết ngày 1/1 là ngày thứ mấy, 11 tháng còn lại chỉ xê dịch xung quanh ngày này thôi:

{2015, 1, 1, 4},  //+0 day(s) from month 1
{2015, 2, 1, 0},  //+3
{2015, 3, 1, 0},  //+3
{2015, 4, 1, 3},  //+6
{2015, 5, 1, 5},  //+1
{2015, 6, 1, 1},  //+4
{2015, 7, 1, 3},  //+6
{2015, 8, 1, 6},  //+2
{2015, 9, 1, 2},  //+5
{2015, 10, 1, 4}, //+0
{2015, 11, 1, 0}, //+3
{2015, 12, 1, 2}  //+5

thành ra được mảng:

static const int wdMGap[] = { //week day month gap
    0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5
};

rồi update 3 dòng code cũ kia, thêm cái mảng này với 1 dòng nữa là ra:

static const int wdMGap[] = { //week day month gap
    0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5
};
int wd = y - 1901;   //year starts from 1901
wd += wd / 4;        //add leap years
wd += wdMGap[m-1];   //add the corresponding month gap
return (wd + 2) % 7; //+2 to match with 1901/1/1

nhưng chưa hết, còn trong năm nhuận thì sao?

// Test cases for first day of month, leap year
{2000, 1, 1, 6},  //+0
{2000, 2, 1, 2},  //+3
{2000, 3, 1, 3},  //+3 +1
{2000, 4, 1, 6},  //+6 +1
{2000, 5, 1, 1},  //+1 +1
{2000, 6, 1, 4},  //+4 +1
{2000, 7, 1, 6},  //+6 +1
{2000, 8, 1, 2},  //+2 +1
{2000, 9, 1, 5},  //+5 +1
{2000, 10, 1, 0}, //+0 +1
{2000, 11, 1, 3}, //+3 +1
{2000, 12, 1, 5}, //+5 +1

phân tích ra thì ta thấy chỉ cần 1 thay đổi nhỏ, đó là với m > 2 thì chỉ cần +1 ngày là đủ. Đương nhiên là phải trong năm nhuận mới +1. Vậy chỉ cần thêm 1 dòng nữa:

static const int wdMGap[] = { 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 };
int wd = y - 1901;   //year starts from 1901
wd += wd/4;          //add leap years
wd += wdMGap[m-1];   //add the corresponding month gap
wd += m>2 && y%4==0; //account for months > 2 in leap year
return (wd+2) % 7;   //+1 to match week day of 1901/1/1

cuối cùng là tìm thứ cho ngày bất kì. Cái này dễ nhất chỉ cần cộng d vào wd nữa là hết Nhưng vì ngày đầu tiên là 1 rồi, thành thử phải là wd += d - 1, nhưng khi return ta return (wd+2) % 7, vậy sửa lại là (wd+1)%7 cho wd += d nó đẹp:

static const int wdMGap[] = { 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 };
int wd = y - 1901;   //year starts from 1901
wd += wd/4;          //add leap years
wd += wdMGap[m-1];   //add the corresponding month gap
wd += m>2 && y%4==0; //account for months > 2 in leap year
wd += d;             //add days
return (wd+1) % 7;   //+1 to match week day of 1901/1/1
Hung viết 01:14 ngày 01/10/2018

Source code để làm gì không biết, việc tính ngày tháng năm là việc phổ biến nhất nên trong lập trình Java, Android và mấy ngôn ngữ hiện đại ngày nay đều đã có API để thực hiện.
Lo mà học sử dụng API thì hơn.

Hoàng Thanh Phúc viết 01:16 ngày 01/10/2018

cảm ơn các bạn đã chia sẻ nhé

X viết 01:26 ngày 01/10/2018

Lúc trước rảnh tìm trên internet rồi ngồi code liên quan đến mấy món này.
Tham khảo: https://github.com/minhhuy150894/Time-Calc

Bài liên quan
0