输入日期显示星期几
比如今天是2013年8月2日,星期五。我们现在就是要实现这样一个功能,给定一个日期,得到该日期是星期几。
比如:
日期 |
星期 |
2013年8月2日 |
星期五 |
20130803 |
星期六 |
2013-08-04 |
星期天 |
2013-6-18 |
星期二 |
2014/1/16 |
星期四 |
2000/8/15 |
星期二 |
我们需要解决的问题有如下几点:
1.对输入格式进行归一化处理;
2.计算将来或以前某一天是星期几;
一、对输入格式的归一化处理
我们首先实现对输入格式的归一化处理,程序如下:
// 输入日期的归一化处理 #include <iostream> #include <string> using namespace std; struct date { int year; int month; int day; }; int m_d[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; int is_leap(int year) { // 注意 year % 100 != 0 // year % 4 == 0 // year % 400 == 0 // 这三者的顺序 // 总共4中顺序组合,不同的顺序影响不同的计算效率 if (year % 100 != 0 && year % 4 == 0 || year % 400 == 0) { return 1; } else { return 0; } } bool get_date(const string& str, date& dt) { dt.year = 0; dt.month = 0; dt.day = 0; int y(0), m(0), d(0); string sy, sm, sd; int f = 1; bool full = false, pass_d = false; for (string::size_type i = 0; i != str.size(); ++i) { // if (isdigit(static_cast<int>(str[i]))) // 该语句导致isctype.c中断言错误:unsigned(c + 1) <= 256 // 故改为: if (str[i] >= '0' && str[i] <= '9') { pass_d = false; if (f == 1) { sy += str[i]; if (sy.size() == 4) { ++f; full = true; } } else if (f == 2) { sm += str[i]; if (sm.size() == 2) { ++f; full = true; } } else if (f == 3) { sd += str[i]; if (sd.size() == 2) { ++f; full = true; } } else if (f > 3) { return false; } } else { if (pass_d == false) { pass_d = true; if (full == true) { full = false; } else { ++f; /*if (f > 4) { return false; }*/ } } else { continue; } } } y = atoi(sy.c_str()); m = atoi(sm.c_str()); d = atoi(sd.c_str()); if (m < 1 || m > 12) { return false; } else { if (d < 1 || d > m_d[is_leap(y)][m]) { return false; } } dt.year = y; dt.month = m; dt.day = d; return true; } string uni_date(const date& dt) { string ret; char tmp[1000]; itoa(dt.year, tmp, 10); ret += tmp; ret += '-'; if (dt.month < 10) { ret += '0'; } itoa(dt.month, tmp, 10); ret += tmp; ret += '-'; if (dt.day < 10) { ret += '0'; } itoa(dt.day, tmp, 10); ret += tmp; return ret; } int main() { string str; while (1) { cout << "输入:"; cin >> str; date dt; cout << "输出:"; if (get_date(str, dt)) { cout << uni_date(dt) << endl; } else { cout << "输入日期非法!" << endl; } cout << endl; } }
二、计算将来或以前某一天是星期几
这里我们需要有个参照点,就以今天为参照点:20130802——星期五,我们首先计算将来某一天或以前某一天相对于今天相差几天,然后根据相差天数推算出具体是星期几。
具体程序如下:
// 计算将来或以前某一天是星期几 #include <iostream> #include <string> using namespace std; struct date { int year; int month; int day; int weekday; static int m_d[2][13]; static int y_d[2]; static string d_w[8]; }; int date::m_d[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; int date::y_d[2] = {365, 366}; string date::d_w[8] = {"", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"}; int is_leap(int year) { // 注意 year % 100 != 0 // year % 4 == 0 // year % 400 == 0 // 这三者的顺序 // 总共4中顺序组合,不同的顺序影响不同的计算效率 if (year % 100 != 0 && year % 4 == 0 || year % 400 == 0) { return 1; } else { return 0; } } bool get_date(const string& str, date& dt) { dt.year = 0; dt.month = 0; dt.day = 0; int y(0), m(0), d(0); string sy, sm, sd; int f = 1; bool full = false, pass_d = false; for (string::size_type i = 0; i != str.size(); ++i) { // if (isdigit(static_cast<int>(str[i]))) // 该语句导致isctype.c中断言错误:unsigned(c + 1) <= 256 // 故改为: if (str[i] >= '0' && str[i] <= '9') { pass_d = false; if (f == 1) { sy += str[i]; if (sy.size() == 4) { ++f; full = true; } } else if (f == 2) { sm += str[i]; if (sm.size() == 2) { ++f; full = true; } } else if (f == 3) { sd += str[i]; if (sd.size() == 2) { ++f; full = true; } } else if (f > 3) { return false; } } else { if (pass_d == false) { pass_d = true; if (full == true) { full = false; } else { ++f; /*if (f > 4) { return false; }*/ } } else { continue; } } } y = atoi(sy.c_str()); m = atoi(sm.c_str()); d = atoi(sd.c_str()); if (m < 1 || m > 12) { return false; } else { if (d < 1 || d > date::m_d[is_leap(y)][m]) { return false; } } dt.year = y; dt.month = m; dt.day = d; return true; } string uni_date(const date& dt) { string ret; char tmp[1000]; itoa(dt.year, tmp, 10); ret += tmp; ret += '-'; if (dt.month < 10) { ret += '0'; } itoa(dt.month, tmp, 10); ret += tmp; ret += '-'; if (dt.day < 10) { ret += '0'; } itoa(dt.day, tmp, 10); ret += tmp; return ret; } string cal_weekday(date& dt) { string dt_str = uni_date(dt); string ref_str = "20130802"; date ref_dt; ref_dt.year = 2013; ref_dt.month = 8; ref_dt.day = 2; ref_dt.weekday = 5; bool fut; date bigger, smaller; if (dt_str >= ref_str) { fut = true; bigger = dt; smaller = ref_dt; } else { fut = false; bigger = ref_dt; smaller = dt; } int smaller_days = 0, bigger_days = 0; for (int m = 1; m < smaller.month; ++m) { smaller_days += date::m_d[is_leap(smaller.year)][m]; } smaller_days += smaller.day; for (int y = smaller.year; y < bigger.year; ++y) { bigger_days += date::y_d[is_leap(y)]; } for (int m = 1; m < bigger.month; ++m) { bigger_days += date::m_d[is_leap(bigger.year)][m]; } bigger_days += bigger.day; int diff = bigger_days - smaller_days; if (fut) { dt.weekday = (ref_dt.weekday + diff) % 7; } else { dt.weekday = ((ref_dt.weekday + 7) - (diff % 7)) % 7; } // 当为星期天时,dt.weekday为0,所以根据date::d_w[]需要做一下特殊处理 if (dt.weekday == 0) { dt.weekday = 7; } return date::d_w[dt.weekday]; } int main() { string str; while (1) { cout << "输入:"; cin >> str; date dt; cout << "输出:"; if (get_date(str, dt)) { cout << uni_date(dt) << endl; } else { cout << "输入日期非法!" << endl << endl; continue; } cout << cal_weekday(dt) << endl; cout << endl; } }
三、总结
本文的初衷是想根据给定的日期得到其对应的星期。首先,我们对于输入的日期做了一个归一化处理,一是为了方便用户输入方便,二是为了我们后续处理的便捷。然后,我们对归一化处理后的日期进行计算,根据一个参照点(20130802——星期五)得到早于或晚于该天的星期。