在程序设计中,日期时间的处理常常会遇到。在C语言程序设计的一些教材中会出现以下例子或习题。php
【例1】第几天? (HDU 2005)编程
给定一个日期,输出这个日期是该年的第几天。
数组
Input
输入数据有多组,每组占一行,数据格式为YYYY/MM/DD组成,具体参见sample input ,另外,能够向你确保全部的输入数据是合法的。
学习
Output
对于每组输入数据,输出一行,表示该日期是该年的第几天。
spa
Sample Input
1985/1/20
2006/3/12
设计
Sample Output
20
71get
(1)编程思路1。input
对于month月,须要累计1~month-1月的各个月份的天数。例如,month等于8,须要累计1~7月的天数,即d=0+31(1月)+28(或2九、2月天数)+31(3月)+30(4月)+31(5月)+30(6月)+31(7月),这个操做能够写成循环,如:it
d=0;io
for( i=1; i<=month-1; i++)
d=d+第i月的天数;
但也能够不写成循环,用switch…case结构来解决。由于,大的月份必定包含小的月份的累计,所以,在case常量表达式的安排时,能够从大到小,而且每一个入口进入后,不用break语句退出switch结构,这样能够完成累计,具体描述为:
d=0;
switch(month-1)
{
case 11:d+=30;
case 10:d+=31;
case 9:d+=30;
case 8:d+=31;
case 7:d+=31;
case 6:d+=30;
case 5:d+=31;
case 4:d+=30;
case 3:d+=31;
case 2:d+=28(或d+=29);
case 1:d+=31;
}
另外,在程序中,须要判断某一年是否闰年,由于闰年的2月份为29天,而非闰年的2月份为28天。
闰年的断定条件是:①能被4整除,但不能被100整除的年份都是闰年,如1996年,2004年是闰年;②能被100整除,又能被400整除的年份也是闰年。如2000年是闰年。能够用一个逻辑表达式来表示:
(year%4==0&&year%100! =0) | | year%400==0
当year为某一整数值时,若是上述表达式值为true(1),则year为闰年;不然year为非闰年。
(2)源程序1。
#include <stdio.h>
int main()
{
int year,month,day,d;
while (scanf("%d/%d/%d",&year,&month,&day)!=EOF)
{
d=0;
switch(month-1)
{
case 11:d+=30;
case 10:d+=31;
case 9:d+=30;
case 8:d+=31;
case 7:d+=31;
case 6:d+=30;
case 5:d+=31;
case 4:d+=30;
case 3:d+=31;
case 2:d+=28;
if (year%4==0 && year%100!=0 || year%400==0) d++;
case 1:d+=31;
}
d=d+day;
printf("%d\n",d);
}
return 0;
}
(3)编程思路2。
学习过数组后,咱们能够将每月的天数保存在数组table[13]中,其中table[i]的值为第i月的天数。这样用一个循环完成累加便可。2月先保存默认天数28,对闰年进行特别处理。
这样写出的程序更简洁。在咱们学习的过程当中,应将写出简洁高效的程序做为本身程序设计的风格和目标。
(4)源程序2。
#include <stdio.h>
int main()
{
int table[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int year,month,day,d,i;
while (scanf("%d/%d/%d",&year,&month,&day)!=EOF)
{
d=0;
for (i=1;i<=month-1;i++)
d+=table[i];
if (month>2 && (year%4==0 && year%100!=0 || year%400==0))
d++;
d=d+day;
printf("%d\n",d);
}
return 0;
}
【例2】几月几日。
输入一个年份year和一个整数d,求year年的第d天是几月几日? 例如,输入2006 71,输出应为3 12,即2006年的第71天是3月12日。
(1)编程思路。
执行例1中程序的逆过程。为简化计,程序中采用二维数组来分别保存非闰年和闰年各月的天数。用循环先肯定第d天前有多少月,减去各月的天数后,剩余的就是几日。
(2)源程序。
#include <stdio.h>
int main()
{
int table[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 year,month,day,d,leap;
while (scanf("%d %d",&year,&d)!=EOF)
{
month=1;
if (year%4==0 && year%100!=0 || year%400==0)
leap=1;
else
leap=0;
while (d>table[leap][month])
{
d-=table[leap][month];
month++;
}
day=d;
printf("%d %d\n",month,day);
}
return 0;
}
【例3】今天星期几。
输入一个日期的年、月、往后,输出该日期是星期几。
(1)编程思路。
设变量year、month和day分别表示输入的年、月和日。在例1中咱们求了一个日期是当年的第几天(设为d),因为一个星期有7天,所以,若是咱们知道该年的元旦是星期几(设为week),那么该日期是星期几就能够肯定了,计算公式为:(week+d-1)%7。0表明星期日。
怎样求年号为year这年的元旦是星期几呢?用一个简单公式便可计算出来。
已知 公元 1 年 1月 1日 为星期一。别问为何,日历编撰的起点,就是这么规定了。
咱们知道一年有365天(固然闰年会有366天,先无论了),每7天1周,365%7=1。即若不考虑闰年,则每一年的元旦是星期几应该是上一年元旦星期几的后一天。
因为 1 年元旦是星期一,所以 2年元旦星期二,3年元旦星期三,4年元旦星期四,…即
week =(year)%7。
因为闰年的存在会在2月多一天,所以,闰年的下一年元旦星期几应再加1,即 5年为星期六(不是星期五,由于 4年是闰年),所以须要知道前year-1年中有多少个闰年。闰年的规则简述就是每4年一个闰年,每100年不是闰年,每400年又是闰年。按集合包含与容斥规则,闰年个数有 (year-1)/4 - (year-1)/100 + (year-1)/400。
所以,已知年号year,就能够根据year计算出该年元旦是星期几。计算公式以下:
week=[ year+(year-1)/4-(year-1)/100+(year-1)/400]%7;
(2)源程序。
#include <stdio.h>
int main()
{
int table[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
char str[7][3]={"日","一","二","三","四","五","六"};
int year,month,day,d,i,week;
while (scanf("%d/%d/%d",&year,&month,&day)!=EOF)
{
week=(year+(year-1)/4-(year-1)/100+(year-1)/400)%7;
d=0;
for (i=1;i<=month-1;i++)
d+=table[i];
if (month>2 && (year%4==0 && year%100!=0 || year%400==0))
d++;
d=d+day;
week=(week+d-1)%7;
printf("%d 年 %d 月 %d日 星期%s\n",year,month,day,str[week]);
}
return 0;
}
弄懂了本例的编程思路,能够本身作一下 HDU 2133 “What day is it”。将上面的源程序略做修改便可。
2006年10月21日是杭州电子科技大学50周年校庆日。输入一个2006年的日期,输出其距离校庆日还有多少天。
(1)编程思路。
2006年是非闰年,所以不须要判断闰年。10月21日是当年第294天。根据输入的日期计算该日期是2006年的第几天(设为d),而后根据d与294的大小关系,输出相应的结果。
(2)源程序。
#include <stdio.h>
int main()
{
int table[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int month,day,d,i,t;
scanf("%d",&t);
while (t--)
{
scanf("%d%d",&month,&day);
d=0;
for (i=1;i<=month-1;i++)
d+=table[i];
d=d+day;
if (d<294)
printf("%d\n",294-d);
else if (d==294)
printf("It's today!!\n");
else
printf("What a pity, it has passed!\n");
}
return 0;
}
【例5】今夕何夕。 (HDU 6112)
2019 年10月1日是中华人民共和国建国70周年。这天是星期二。思考这样一个问题:接下来最近的哪一年里的同一个日子,和建国70周年的星期数同样?好比2019年10月1日,星期二。下一个也是星期二的10月1日发生在2024年。
输入一个日期yyyy-mm-dd,输出接下来与该日期的星期数相同的同一个日子的年份。
(1)编程思路。
根据例3的公式能够计算出year年元旦是星期几(设为week1),而后用i从year+1年开始穷举,看哪一年的同一个日子的年份的星期符合要求。
因为两个日期年份不一样,月和日相同,即它们在该年属于第几天相差最多为1(由于闰年的缘故)。所以能够根据公式计算出穷举的第i年元旦是学期几(设为week2)。
若给定日期在1月或2月(2月29日做为特例特别处理,其方法是穷举下一个闰年),则只要week1==week2,第i年即为所求。
若给定日期的月份大于3月,需考虑闰年的问题。若第year和第i年均是闰年或均不是闰年,无需校订,直接比较week1和week2便可。
若第year年是闰年而第i年不是闰年,因为相同的日子,第year年会比第i年多一天,所以应该week1+1==week2,两个日期的星期数才相同。将week2用表达式 week2=(week2-1+7)%7 校订一下。
若第year年不是闰年而第i年是闰年,因为相同的日子,第year年会比第i年少一天,所以应该week1-1==week2,两个日期的星期数才相同。将week2用表达式 week2=(week2+1)%7 校订一下。
这样再比较 week1和week2是否相等才行。
(2)源程序。
#include <stdio.h>bool isLeap(int year){ if (year%4==0 && year%100!=0 || year%400==0) return true; else return false;}int main(){ int year,month,day,t,week1,week2,i; scanf("%d",&t); while(t--) { scanf("%d-%d-%d",&year,&month,&day); week1=(year+(year-1)/4-(year-1)/100+(year-1)/400)%7; for (i=year+1;i<=9999;i++) { if (month==2&&day==29&&!isLeap(i)) // 2月29日特别处理 continue; week2=(i+(i-1)/4-(i-1)/100+(i-1)/400)%7; if(month>2) { if (isLeap(year) && ! isLeap(i)) week2=(week2-1+7)%7; if (!isLeap(year) && isLeap(i)) week2=(week2+1)%7; } if (week1==week2) { printf("%d\n",i); break; } } } return 0; }