```cpp = #include <stdlib.h> #include <cstdio> #include <iostream> bool isLeapYear(int year); class Date{ public: Date(int d, int m, int y){ day = d; month = m; year = y; } static void DayOfWeek(const Date& date) { //確認日期是否在格里高曆或儒略曆 if(date.isGregorian()){ std::string dayOfWeek= date.getDoW(date.zeller(date.day, date.month, date.year)); printf("%s %d, %d is %s\n", date.getMName(date.month).c_str(), date.day,date.year, dayOfWeek.c_str()); } else if (date.isWithinTransition())//若都不是則日期無效 { printf(" Date invalid \n"); return; }else{ std::string dayOfWeek= date.getDoW(date.zeller(date.day+10, date.month, date.year)); printf("%s %d, %d is %s\n", date.getMName(date.month).c_str(), date.day,date.year, dayOfWeek.c_str()); }} static void DateSub(const Date& date1, const Date& date2) { //確認日期是否有效 if (date1.isWithinTransition()||date2.isWithinTransition()){ printf("Date invalid \n"); return; } //每月天數 [0] 代表一月很反直覺 因此直接使 [n] 代表 n 月 int dayInMonth[]= {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int days1 = date1.day; for (int m = 1; m < date1.month; ++m) { days1 += dayInMonth[m]; } // 運算西元元年至當日的總天數 days1+=365*date1.year+date1.leapUntilYear(date1.year); int days2 = date2.day; for (int m = 1; m < date1.month; ++m) { days2 += dayInMonth[m]; } days2+=365*date2.year+date2.leapUntilYear(date2.year); //兩者相減取絕對值 int diff=abs(days2-days1); //由於格里高曆和儒略曆的間隔發生在1582/10/4 ~ 1582/10/15 因此此前採用儒略曆法 此後採用格里高曆法 if(!((date1.isGregorian() && date2.isGregorian())||(!date1.isGregorian() && !date2.isGregorian()))){ diff-=10; } printf("%d days from %s %d, %d to %s %d, %d\n", diff, date1.getMName(date1.month).c_str(), date1.day, date1.year, date2.getMName(date2.month).c_str(), date2.day,date2.year); } static void DateAdd(const Date& date1, const int n,const int token){ //確認日期是否有效 if(date1.isWithinTransition()&&!token){ printf("Date invalid \n"); return; } int dayInMonth[]= {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int totalDays=date1.day; //計算至今日期總和 totalDays +=365*date1.year+date1.leapUntilYear(date1.year); for (int m = 1; m < date1.month; ++m) { totalDays += dayInMonth[m]; } if (date1.month <= 2 && isLeapYear(date1.year)) { totalDays--; } totalDays+=n; int newYear=0; //計算新日期年分 while(totalDays>=365) { totalDays-=365; newYear++; if(isLeapYear(newYear)) totalDays--; } int newMonth = 0; int newDay = 0; for (int m = 1; m <= 12; ++m) { int daysInMonth = dayInMonth[m]; if (totalDays <= daysInMonth) { newMonth = m; if(m==2 &&isLeapYear(newYear)) totalDays+=1; newDay = totalDays; break; } totalDays -= daysInMonth; } Date newDate(newDay, newMonth, newYear); //token=1 代表二次或以上運算 需要改變輸出 if(!token){ printf("%d days after %s %d, %d ",n, date1.getMName(date1.month).c_str(), date1.day, date1.year); } if (date1.isGregorian()&&!newDate.isGregorian()) { DateAdd(newDate, -10,1); } else if (!(date1.isGregorian()||date1.isWithinTransition())&&(newDate.isGregorian()||newDate.isWithinTransition())) { DateAdd(newDate, 10,1); } else{ printf("is %s %d, %d\n", date1.getMName(newMonth).c_str(), newDay,newYear); } } private: int day; int month; int year; //to check if the date is a gregorian date bool isGregorian() const { return (year > 1582 || (year == 1582 && (month > 10 || (month == 10 && day >= 15)))); } //get month name std::string getMName(int month) const{ const char* monthNames[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; return monthNames[month - 1]; } //to check if the date is within the transition period bool isWithinTransition() const { return (year == 1582 && month == 10 && day >= 5 && day <= 14); } std::string getDoW(int token) const{ const char* dayOfWeek[] = { "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" }; return dayOfWeek[token]; } //zeller's congruence //formula from https://www.geeksforgeeks.org/zellers-congruence-find-day-date/ int zeller(int day, int month, int year) const{ if(month<3){ month += 12; year--; } int k = year % 100; int j = year / 100; return (day+(13*(month+1))/5+k+k/4+j/4+5*j)%7; } //to calculate the number of leap year until the given year int leapUntilYear(int y) const{ return y / 4 - y / 100 + y / 400; } }; int main() { char input[100]; //事先讀取所有數據 while (scanf("%99[^\n]", input) == 1) { int dayInMonth[]= {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int day1, month1, year1,day2, month2, year2; int n; //依照數據輸入格式選擇不同算式 if ((sscanf(input,"%d/%d/%d - %d/%d/%d", &year1, &month1, &day1, &year2, &month2, &day2)) ==6) { if(day1<0||day2<0||month1<0||month2<0||month1>13||month2>13||(day1>dayInMonth[month1]&&(!isLeapYear(year1)&&(month1==2)&&(day1>29))) ||day2>dayInMonth[month2]&&(month2==2&&(!isLeapYear(year2)&&(month2==2)&&(day2>29)))){ printf("Date invalid \n"); exit(1); } Date date1(day1, month1, year1), date2(day2,month2,year2); Date::DateSub(date1, date2); } else if ((sscanf(input,"%d/%d/%d + %d", &year1, &month1,&day1,&n))==4){ if (day1<0||month1<0||month1>13||(day1>dayInMonth[month1]&&(!isLeapYear(year1)&&(month1==2)&&(day1>29)))){ printf("Date invalid \n"); exit(1); } Date date(day1, month1, year1); Date::DateAdd(date, n,0); } else if ((sscanf(input,"%d/%d/%d", &year1, &month1, &day1))==3) { if(day1<0||month1<0||month1>13||(day1>dayInMonth[month1]&&(!isLeapYear(year1)&&(month1==2)&&(day1>29)))){ printf("Date invalid \n"); exit(1); } Date date(day1, month1, year1); Date::DayOfWeek(date); } if ((sscanf(input,"%d", &day1)==1 && day1==-1)) break; } return 0; } //確認 year是否為閏年 bool isLeapYear(int year){ return ((year % 4 == 0 && year % 100!= 0) || year % 400 == 0); } ```