2017-06-12 9 views
1

私は、ユーザが日付をYYYY-MM-DDフォーマットで入力するように、Cで基本日付計算機を作成する必要があります。私はそれの基本を持っています。私はする必要はありませんが、私は少し余裕を持ち、うるう年を考えていきたいと思います。プログラムは正常に動作します。ただし、うるう年は正しく計算されません。私が2016-02-26の日付を入力するとき、私は2016-03-04の期待される結果を持っているはずですが、私は2016-03-03の結果を得ます。私はモジュロを使って次のような効果を得るためにif else文を使用したとします。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

注:あなたが最初のd1.monthは1と12の間にあることを確認した場合は、よりコンパクトな単一のテストに上記のテストを凝縮することができます。 1901年から2099年の間は何年もOKです。 1900年と2100年には失敗します(いずれもうるう年でした)。年が400で割り切れる場合は、うるう年です。それ以外の場合、年が100で割り切れる場合は、うるう年ではありません。それ以外の場合は、年が4で割り切れる場合は、うるう年です。そうでなければ、そうではありません。これは結果を計算するための最良のシーケンスではありません。それはルールを与えるためです。 –

+0

@JonathanLeffler:うるう年の計算は実際には完全に壊れています.1700,1800,1900,2100の正しい結果しか得られません。 – chqrlie

+0

@chqrlie:Urg!あなたが正しいかのように見える - 私は条件の暗示的な逆転に気付かなかった。まあ、私は言い訳として使用することに "私は問題があることを認識した"と "私は正しいアルゴリズムを診断したと思う"に減らされる。カレンダーの計算は、グレゴリオ暦のロココ(バロックではないにせよ)の性質のために非常に厄介です。 –

答えて

2

もスタートのためにこれは、それは常にtrueになります

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

間違っています。あなたはそれがないと思う何をしません

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

興味深いことに、これは私が予想していたものとは異なる結果を出していたので、これは新しいバグ(誤った...予期しない機能)を導入したと思った。しかし、プログラムには当日が含まれていないことがわかりました。それで、それは1週間と1日の答えを与える。 – RLuck

2

これを必要とする:

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

あなたは、このような値のリストに一つの値を比較することはできません。あなたが実際にやっていることはこれです:

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

あなたが値1に対してd1.monthを比較しているが、その後、あなたがそのブール結果を取ると、論理OR他のいくつかの数字で操作を行います。これらの数値はすべて0ではないので、この式は常に真と評価されます。

同じことが、このために行く:

:あなたが実際にフォールスルー例で switchとよりきれいにこれを行うことができます

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

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

あなたが明示的にそれぞれの値と比較する必要があります

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

は常にtrueと評価され、falseではありません。 – pm100

+0

@ pm100良いキャッチです。一定。 – dbush

1

コードに複数の問題があります。

  • 閏年のテストは正しくありません。(d1.month == 2 && d1.year % 4)は、閏年ではない1901年から2099年の通常の年を示します。

    if (d1.month == 2) { 
        daysInMonth = (d1.year % 4 || (!(d1.year % 100) && (d1.year % 400)) ? 28 : 29; 
    } 
    
    :完全なテストは、このているようしかしそれはグレゴリオ改質暦によれば、また、400の倍数でない100の年の倍数が、閏年れない

    if (d1.month == 2 && (d1.year % 4) == 0) //Attempt to calculate leap year 
        daysInMonth = 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ステートメントを使用します。あなたのうるう年の計算がずさんであることを

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です。決定的な答えを出す前にテストする条件が少なくなります。 –