【面试题】日期计算

《程序员面试宝典》一书中有题目如下:

编写一个函数,要求输入年、月、日、时、分、秒,输出该时间的下一秒。

如输入2007年12月31日23时59分59秒,则输出2008年1月1日0时0分0秒。

书中给的解答代码如下(后面给出一个比较好的做法):

// 输入时间,将该时间加1秒,结果通过参数返回。成功返回0,失败返回-1
int ResetTime(int *year, int *month, int *day, int *hour, int *minute, int *second)
{
    // 检查指针是否有效
    if(NULL == year || NULL == month || NULL == day || NULL == hour || NULL == minute || NULL == second)
    {
        return -1;
    }

    // 检查日期是否合法
    if(*year < 0 || *month < 1 || *month > 12 || *day < 1 || *day > 31 ||
       *hour < 0 || *hour > 23 || *minute < 0 || *minute > 59 || *second < 0 || *second > 59)
    {
       return -1;
    }
    if(*month == 2 || *month == 4 || *month == 6 || *month == 9 || *month == 11)
    {
        if(*day > 30)
        {
            return -1;
        }
    }
    if(0 == (*year % 400) || (0 == *year %4 && 0 != *year % 100))
    {
        if(*day > 29 && (2 == *month))
        {
            return -1;
        }
    }
    else
    {
        if(*day > 28 && (2 == *month))
        {
            return -1;
        }
    }

    // 每月天数数组,暂时按非闰年
    int dayOfMonth[12] = {31,28,31,30,31,30,31,31,30,31,30,31};

    // 如果是闰年更新数组
    if(0 == (*year % 400) || (0 == *year %4 && 0 != *year % 100))
    {
        dayOfMonth[1] = 29;
    }

    // 执行秒数加1计算
    *second += 1;
    if(*second >=60)
    {
        *second = 0;
        *minute += 1;
        if(*minute >= 60)
        {
            *minute = 0;
            *hour += 1;
            if(*hour >= 24)
            {
                *hour = 0;
                *day += 1;
                if(*day > dayOfMonth[*month -1])
                {
                    *day = 1;
                    *month += 1;
                    if(*month > 12)
                    {
                        *month =1;
                        *year += 1;
                    }
                }
            }
        }
    }

    return 0;
}

注:对原书代码做了修改,主要是入参检查部分、函数返回值部门,主要算法未变。

尽管题目只要求对秒数加1,但我想或许可以把函数写得更开放些,可以让秒数加(减)一定的秒数。

做法主要使用日期计算函数:

  • 先将输入时间转换成自1970年1月1日0时0分0秒起至输入时间经过的秒数,得到输入时间的秒数;
  • 将输入时间的秒数做加减操作;
  • 将输入时间转换成年月日时分秒;
代码如下:

// 输入时间,将该时间增加time_diff秒,结果通过参数返回。成功返回0,失败返回-1
int TimeOper(int *year, int *month, int *day, int *hour, int *minute, int *second, int time_diff)
{
    // 检查指针是否有效
    if(NULL == year || NULL == month || NULL == day || NULL == hour || NULL == minute || NULL == second)
    {
        return -1;
    }

    // 检查日期是否合法
    if(*year < 0 || *month < 1 || *month > 12 || *day < 1 || *day > 31 ||
       *hour < 0 || *hour > 23 || *minute < 0 || *minute > 59 || *second < 0 || *second > 59)
    {
       return -1;
    }
    if(*month == 2 || *month == 4 || *month == 6 || *month == 9 || *month == 11)
    {
        if(*day > 30)
        {
            return -1;
        }
    }
    if(0 == (*year % 400) || (0 == *year %4 && 0 != *year % 100))
    {
        if(*day > 29 && (2 == *month))
        {
            return -1;
        }
    }
    else
    {
        if(*day > 28 && (2 == *month))
        {
            return -1;
        }
    }

    // 将输入的时间转换成自1970年1月1日0时0分0秒起至输入时间止所经过的秒数
    if(*year < 1970)
    {
        return -1;
    }

    // 将输入时间写入struct tm结构
    struct tm input_time;
    input_time.tm_year = *year -1900; // 自1900年算起至今的年数
    input_time.tm_mon = *month;
    input_time.tm_mday = *day;
    input_time.tm_hour = *hour;
    input_time.tm_min = *minute;
    input_time.tm_sec = *second;

    // 取得自1970年起至输入日期所经过的秒数,执行运算
    time_t input_seconds = mktime(&input_time);
    input_seconds += time_diff;

    // 将计算后的秒数转换成日期格式
    //struct tm *pout_time = gmtime(&input_seconds);
    struct tm *pout_time = localtime(&input_seconds);
    *year = pout_time->tm_year + 1900;
    *month = pout_time->tm_mon;
    *day = pout_time->tm_mday;
    *hour = pout_time->tm_hour;
    *minute = pout_time->tm_min;
    *second = pout_time->tm_sec;

    return 0;
}

注:mktime只支持1970年以后的年份,这也是本函数的一个限制。另外mktime、localtime都是经过时区转换的,不会有问题。如果使用gmtime替换localtime得到的结果是不正确的。

题目要求简单,如果能做得更通用些,给面试官的印象可能更好些。

也许第一个函数可以修改一下,可以让函数应用范围更广一些。但逻辑也较复杂一些。

例如:像第二个函数一样增加一个参数指示加(减)的秒数,秒做完运算后要计算秒改变了多少分,然后分运算、时运算... ...。

2011-11-07 任洪彩 [email protected]

转载请注明出处:http://my.oschina.net/renhc/blog

 

你可能感兴趣的:(面试题,c/c++,日期计算)