2017-06-12 55 views
1

我需要在C中創建一個基本日期計算器,用戶輸入日期格式爲YYYY-MM-DD。我有它的基礎知識。雖然我不需要,但我想要多花一點時間並考慮閏年。該程序運行良好;但是,它不能正確計算閏年。當我輸入日期2016-02-26時,我應該得到2016-03-04的預期結果,但我得到2016-03-03的結果。我認爲,如果我使用模數的話,使用if else語句來實現以下效果。在C中創建日期計算器C

if (month == 2 && year % 4) days = 29; 
    else days = 28; 

這裏是我完整的代碼...

//Does not require <stdlib.h> 
#include <stdio.h> 

// Set variables 
int newDay, newMonth, newYear, daysInMonth, daysRemain; 
// Set structure for day month year 
struct date { 
    int day, month, year; 
}; 
// set structure for date 
struct date d1; 

int main (void) { 
    //Intro 
    printf("Date calculation program by Keith A. Russell"); 
    //Asks for user input 
    printf("\n\nPlease enter the year in four digit format (YYYY) "); 
    scanf("%i", &d1.year); 
    printf("\nEnter the month in two digit format (MM) "); 
    scanf("%i", &d1.month); 
    printf("\nEnter the day in two digit format (DD) "); 
    scanf("%i", &d1.day); 
    //Runs calculations to increase the date by a week 
    newDay = d1.day + 7; 
    newMonth = d1.month; 
    newYear = d1.year; 
    daysRemain = 0; 
    //For if the next week is going to be greater than the next month 
    if (newDay > 28) 
     checkMonth(); //Runs checkMonth Function 
    //Prints the dates 
    printf("\nThe new date is %i-%i-%i: \n", newYear, newMonth, newDay); 
} 

checkMonth() { 
    if (d1.month == 1 || 3 || 5 || 7 || 8 || 10 || 12) 
     daysInMonth = 31;    //For months with 31 days 
    if (d1.month == 2 && d1.year % 4) //Attempt to calculate leap year 
     daysInMonth = 29; 
    else { 
     daysInMonth = 28;   //All other years 
    } 
    if (d1.month == 4 || 6 || 9 || 11) //For months with 30 days 
     daysInMonth = 30; 
    //Sets up to advance the year if approaching the end of year 
    if (newDay > daysInMonth) { 
     daysRemain = newDay - daysInMonth; 
     newDay = daysRemain; 
     newMonth++; 
     checkYear(); 
    } 
} 
//Runs function to advance to the next year 
checkYear() { 
    if (d1.month == 12) 
     if (daysRemain > 0) { 
      newYear++; 
      newMonth = 1; 
     } 
} 

如果有計算閏年和它包括在該計劃的更優雅的方式,我很感激很大。謝謝。

+0

請注意,您的閏年的計算是草率的。在1901年至2019年範圍內可以使用多年;它在1900年和2100年都沒有通過(這兩次都不是閏年)。如果年份可以被400整除,那就是閏年;否則,如果年可以被100整除,那不是閏年;否則,如果年可以被4整除,那麼這是一個閏年;否則,它不是。這不是計算結果的最佳順序;但是,這是爲了給規則。 –

+0

@JonathanLeffler:閏年計算實際上已經完全被破壞:它只能產生1700,1800,1900,2100的正確結果... – chqrlie

+0

@chqrlie:Urg!看起來你是對的 - 我沒有注意到這種情況的隱含倒置。那麼,我淪落爲藉口「我認識到有一個問題」和「我認爲我診斷出了正確的算法」。由於公曆日曆的洛可可(如果不是巴洛克式的)性質,日曆計算顯得非常令人滿意。 –

回答

2

很好的開始,這是錯誤的

if (d1.month == 1 || 3 || 5 || 7 || 8 || 10 || 12) 

這將永遠是正確的。您需要

if (d1.month == 1 || d1.month == 3 || d1.month == 5 ....) 
+0

有趣的是,我認爲這引入了一個新的錯誤(錯誤...意外功能),因爲它給出了與我預期不同的結果。但我確實發現該程序不包括輸入的日期。所以它給出了一週和一天的答案。 – RLuck

2

這不會做你認爲它的作用:

if (d1.month == 1 || 3 || 5 || 7 || 8 || 10 || 12) 

您可以在一個價值比不上這樣值的列表。你實際上做的是這樣的:

if ((d1.month == 1) || 3 || 5 || 7 || 8 || 10 || 12) 

你比較d1.month對值1,但你採取的布爾結果,並做邏輯或與其他幾個號碼。由於所有這些數字都是非零的,所以這個表達式總是會計算爲真。

這同樣適用於這樣的:

if (d1.month == 4 || 6 || 9 || 11) 

你需要明確與之比較的每個值:

if ((d1.month == 1) || (d1.month == 3) || (d1.month == 5) ... 

你可以用switch與下通的情況下真正做到這一點更乾淨

switch (d1.month) { 
case 1: 
case 3: 
case 5: 
case 7: 
case 8: 
case 10: 
case 12: 
    daysInMonth = 31; 
    break; 
case 4: 
case 6: 
case 9: 
case 11: 
    daysInMonth = 30; 
    break; 
case 2: 
    // years divisible by 100 are not leap years, unless they are also divisible by 400 
    daysInMonth = (d1.year % 400 == 0) ? 29 : 
        (d1.year % 100 == 0) ? 28 : 
        (d1.year % 4 == 0) ? 29 : 28; 
    break; 
} 
+0

總是評價爲真,而不是假 – pm100

+0

@ pm100良好的捕獲。固定。 – dbush

1

你的代碼有多個問題:

  • 測試閏年是不正確的:(d1.month == 2 && d1.year % 4)表示1901和2099是平年間正常年份。正確的測試是這樣的:

    if (d1.month == 2 && (d1.year % 4) == 0) //Attempt to calculate leap year 
        daysInMonth = 29; 
    

    不過請注意,根據陽曆改革的日曆,那不也是400的倍數爲100年的倍數不是閏年,所以完整的測試是這樣的:

    if (d1.month == 2) { 
        daysInMonth = (d1.year % 4 || (!(d1.year % 100) && (d1.year % 400)) ? 28 : 29; 
    } 
    
  • 您的月份值測試是不正確的:不是if (d1.month == 1 || 3 || 5 || 7 || 8 || 10 || 12),你應該寫:

    if (d1.month == 1 || d1.month == 3 || d1.month == 5 || d1.month == 7 || 
        d1.month == 8 || d1.month == 10 || d1.month == 12) 
    

爲了使代碼更具可讀性,您可以使用switch語句。如果您首先檢查d1.month是1到12之間,則您可以將上面的測試到一個更緊湊的單個測試:

if ((1 << d1.month) & ((1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 8) | (1 << 10) | (1 << 12))) { 
    daysInMonth = 31; 
} 
+0

使用'if(d1.month == 4 || d1.month == 6 || d1.month == 9 || d1.month == 11)'可能會更快一些,並使用30天是真的,否則31;在提出明確答案之前測試的條件較少。 –