在前面,我们分别利用泰勒公式和C标准库中的mktime()函数推算了某个特定日期所对应的星期几,刚做完这些,就又遇到了一个与日期相关的新任务:
老板把每个月例会的时间定在了每个月的第一个星期一,他让我把具体日期整理出来,发给每一个成员,提醒大家准时参加。
简单地讲,也就是把每个月的第一个星期一对应的日期提取出来。如果时间范围比较短(比如一年),自己翻翻日历勉强也能解决,如果要是时间范围比较长(比如十年),再去一个个翻日历,就麻烦了。怎么办?
还记得我们在学了C语言,如何统计一篇英文文章中的单词数?中所认识和体会到的:
程序,就是用来帮助人们完成这些看起来枯燥繁琐但是带有一定规律性的事情的。
面对这个麻烦而又有一定规律的问题,我们同样可以用C语言写个程序来解决。
如何解决呢?想想我们是如何在日历中找出每个月的第一个星期一的?我们先用1月份的第一个星期一作为起点,然后以七天为一个间隔,查看下一个星期一的日期,如果是新的一个月的星期一,则输出,如果在已经输出的这个月,则继续加上7天向下寻找,知道找完这一年为止。
基本思路就是这样,但是,我们这里还用到了mktime()函数的一个特点,也就是如果输入的分解时间的日期tm_mday超出了其取值范围[0,30],mktime()会将其折算成相邻月份的日期,比如,某个月的tm_mday 为32,而这个月只有30天,mktime()会将其视作下个月的第二天,而不会将其视作日期错误。利用这个特性,我们就可以通过递增tm_mday完成整个一年的遍历访问量了。
按照上面分析的思路,我们可以将其实现如下:
#include <string.h> #include <time.h> #include <stdio.h> #include <stdbool.h> int main() { struct tm t; memset(&,0,sezeof(t)); //用年月日填充分解时间t //这里指定1月中的第一个星期为起点 t.tm_year = 2013 - 1900; // 年份,减去起始年份 t.tm_mon = 1 - 1; // 月份 t.tm_mday = 7; // 2013年1月7日是1月份的第一个星期一 puts("the first mondays in 2013 are"); // 记录已经输出的月份 int lastmon = -1; while(true) { //将分解时间t转换为日历时间ct time_t ct = mktime(&t); if(-1 == ct) //日期错误 { break; } else { //用localtime()函数获取日历时间ct对应的分解时间 struct tm* bt = localtime(&ct); //判断是否在2013年内 if(bt->tm_year != 2013-1900) { break; } //判断这个星期一是否是本月的第一个星期一 if(t.tm_mon != lastmon) { //如果是,输出对应的日期 printf("%d - %d ",bt->tm_mon+1,bt->tm_mday); //记录本月已经输出 lastmon = bt->tm_mon; } t = *bt; //更新日期 t.tm_mday += 7; //检查下一个星期一 } } return 0; }
利用这个函数,我们可以轻松地得到2013年的每个月的第一个星期一对应的日期,可以圆满向老板交差了。
the first mondays in 2013 are
1 – 7, 2 – 4, 3 – 4, 4 – 1, 5 – 6, 6 – 3
7 – 1, 8 – 5, 9 – 2, 10 – 7, 11 – 4, 12 – 2