在程序設計中,日期時間的處理常常會遇到。在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; }