《程序员面试宝典》一书中有题目如下:
编写一个函数,要求输入年、月、日、时、分、秒,输出该时间的下一秒。
如输入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 任洪彩 qdurenhongcai@163.com
转载请注明出处:http://my.oschina.net/renhc/blog