程序最美(寻路)

你还在坚持练习你的技术吗?运动员天天训练,音乐家也会演练更难的曲章。你呢?

输入日期显示星期几

输入日期显示星期几

         比如今天是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——星期五)得到早于或晚于该天的星期。

posted on 2013-08-02 16:25  unixfy  阅读(918)  评论(0编辑  收藏  举报

导航