2016-11-27 22 views
-1

私は2つの関数を使ってCでコードを書いています。Cの2つの日付間の勤務日数を計算する

最初の数字(WorkDay)は、それが稼働日(return 1)かどうか(return 0)であるかどうかを日付で示します。最初の機能はOKだと思いますが、それは良いかもしれませんが、機能しています。私の国には週末や祝日が含まれています。

問題には2つ目の機能(CountWorkDays)が付いています。 2つの日付が必要で、正しい場合は(return 1)、その場合は、入力された日付(cnt=)を含め、その中にいくつの就業日があるかを指定する必要があります。日付が正しくない場合(最初は2番目のものなど)、return 0があります。私は助けの機能をnext_day()にしようとしましたが、間違っていると確信しています。第二の機能で私を助けてくれますか? 私は<time.h>を使用することはできませんし、いくつかのアサートを置いています。

#include <stdio.h> 
#include <math.h> 
#include <assert.h> 

int WorkDay (int y, int m, int d) 
{ 
int h, day; 
h= (d + floor(((m+1)*26)/10) + y + floor(y/4) + 6*floor(y/100) + floor(y/400)); 
day=h%7; 

if ((y%4!=0) && m==2 && d==29) 
    return 0; 
else if (((y%4==0 || y%400==0) && (y%100!=0 || y%4000!=0)) && m==2 && d==29) 
{ 

    if (day==2 || day==3 || day==4 || day==1 || day==0) 
     return 1; 
    else 
     return 0; 
} 
else if ((d==1 && m==1) || (d==1 && m==5) || (d==8 && m==5) || (d==5 && m==7) || (d==6 && m==7) || (d==28 && m==9) || (d==28 && m==10) || (d==17 && m==11) || (d==24 && m==12) || (d==25 && m==12) || (d==26 && m==12) || day==0 || day==1 || (m==1 && (d>31 || d<1)) || (m==2 && (d>29 || d<1)) || (m==3 && (d>31 || d<1)) || (m==4 && (d>30 || d<1)) || (m==5 && (d>31 || d<1)) || (m==6 && (d>30 || d<1)) || (m==7 && (d>31 || d<1)) || (m==8 && (d>31 || d<1)) || (m==9 && (d>30 || d<1)) || (m==10 && (d>31 || d<1)) || (m==11 && (d>30 || d<1)) || (m==12 && (d>31 || d<1)) || y<2000 || m>12 || m<1) 
    return 0; 
else if (day==2 || day==3 || day==4 || day==5 || day==6) 
    return 1; 
else 
    return 0; 
} 


int next_day() 
{ 
int y1, m1, d1; 
static int days_in_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 
unsigned short day_counter; 

    d1 += 1; day_counter++; 
    if (d1 > days_in_month[m1]) 
     { 
     d1 = 1; 
     m1 += 1; 
      if (m1 > 12) 
      { 
      m1 = 1; 
      y1 += 1; 
      if (((y1%4==0 || y1%400==0) && (y1%100!=0 || y1%4000!=0))) 
       { 
       days_in_month[2] = 29; 
       } 
      else 
       { 
       days_in_month[2] = 28; 
       } 
      } 
     } 
return 0; 
} 

int CountWorkDays (int y1, int m1, int d1, 
       int y2, int m2, int d2, 
       int * cnt) 
{ 
int i,x; 
if ((m1==1 && (d1>31 || d1<1)) || (m1==2 && (d1>29 || d1<1)) || (m1==3 && (d1>31 || d1<1)) || (m1==4 && (d1>30 || d1<1)) || (m1==5 && (d1>31 || d1<1)) || (m1==6 && (d1>30 || d1<1)) || (m1==7 && (d1>31 || d1<1)) || (m1==8 && (d1>31 || d1<1)) || (m1==9 && (d1>30 || d1<1)) || (m1==10 && (d1>31 || d1<1)) || (m1==11 && (d1>30 || d1<1)) || (m1==12 && (d1>31 || d1<1)) || y1<2000 || m1>12 || m1<1 ||(m2==1 && (d2>31 || d2<1)) || (m2==2 && (d2>29 || d2<1)) || (m2==3 && (d2>31 || d2<1)) || (m2==4 && (d2>30 || d2<1)) || (m2==5 && (d2>31 || d2<1)) || (m2==6 && (d2>30 || d2<1)) || (m2==7 && (d2>31 || d2<1)) || (m2==8 && (d2>31 || d2<1)) || (m2==9 && (d2>30 || d2<1)) || (m2==10 && (d2>31 || d2<1)) || (m2==11 && (d2>30 || d2<1)) || (m2==12 && (d2>31 || d2<1)) || y2<2000 || m2>12 || m2<1 || y2>y1 || (y1==y2 && m2>m1) || (y1==y2 && m1==m2 && d2>d1)) 
    return 0; 
else 
{ 
while (y1!=y2 && m1!=m2 && d1!=d2) 
{ 
while (next_day()) 
    { 
    if (WorkDay(y1, m1, d1) == 1) 
     i=0; 
     x=i++; 
    } 
} 
*cnt=x; 
return 1; 
} 
} 

int main (int argc, char * argv []) 
{ 
    int cnt; 
    assert (WorkDay (2016, 11, 11)); 
    assert (! WorkDay (2016, 11, 12)); 
    assert (CountWorkDays (2016, 11, 1, 
         2016, 11, 30, &cnt) == 1 
     && cnt == 21); 
    assert (CountWorkDays (2001, 1, 1, 
         2015, 2, 29, &cnt) == 0); 
    return 0; 
} 
+0

以前のZellerの一致の変種を見たことがありません:元のものよりずっと簡単です。フロア((m + 1)* 26)/ 10)ビットの丸め誤差を監視します。私は多くの32ビットマシン実装に.0001を追加しなければならなかった。 – cup

+0

土曜日の代わりに日曜日か月曜日のいずれかを0にするには、数式に1または2を追加することをお勧めします。 – cup

答えて

0

問題はnext_day()およびCountWorkDays()にあります。

  1. next_day()は、ローカル変数d1、m1、y1を使用しています。ランダムな日の次の日を計算しています。
  2. CountWorkDays()では、d1、m1、y1をインクリメントしていません。

対処:

  1. 入力として日を受け取り、出力として次の日に返すように)(NEXT_DAYを変更します。 CountWorkDaysで

    int next_day(int *d, int *m, int *y) 
    { 
        /* Use current day to start. */ 
        int y1 = *y; 
        int m1 = *m; 
        int d1 = *d; 
    
        /* Your code to find next day. Remove day_counter here as it is unnecessary.*/ 
    
        /* Return next day. */ 
        *y = y1; 
        *m = m1; 
        *d = d1; 
        return 0; 
    } 
    
  2. ()以下のようにD1、M1、Y1とNEXT_DAY呼び出します。

else 
{ 
    while (1) 
    { 
     if (y1!=y2 && m1!=m2 && d1!=d2) //Check if end day is reached. 
     { 
      if (WorkDay(y1, m1, d1) == 1) 
       x++; //At the beginning initialize x to 0. 
     } 
     else 
     { 
      break; 
     } 

     next_day(&d1, &m1, &y1); //Get the next day. 
    } 
} 
+0

なぜポインタを渡すことを提案しますか? – alk

+0

@alk私は自分の答えを更新しました。基本的には、next_day()を任意の日の翌日に戻したい。 – MayurK

+0

説明とコードをありがとう!しかし、「WorkDay」の主張はまだ動作しません。(私はCの初心者ですが、他に何が修正されるべきかわかりません。 – anonym

0
int CountWorkDays(int y1, int m1, int d1, int y2, int m2, int d2, int * cnt) 
{ 
    int i, x; 
    if((m1 == 1 && (d1>31 || d1<1)) || (m1 == 2 && (d1>29 || d1<1)) || (m1 == 3 && (d1>31 || d1<1)) || (m1 == 4 && (d1>30 || d1<1)) || (m1 == 5 && (d1>31 || d1<1)) || (m1 == 6 && (d1>30 || d1<1)) || (m1 == 7 && (d1>31 || d1<1)) || (m1 == 8 && (d1>31 || d1<1)) || (m1 == 9 && (d1>30 || d1<1)) || (m1 == 10 && (d1>31 || d1<1)) || (m1 == 11 && (d1>30 || d1<1)) || (m1 == 12 && (d1>31 || d1<1)) || y1<2000 || m1>12 || m1<1 || 
     (m2 == 1 && (d2>31 || d2<1)) || (m2 == 2 && (d2>29 || d2<1)) || (m2 == 3 && (d2>31 || d2<1)) || (m2 == 4 && (d2>30 || d2<1)) || (m2 == 5 && (d2>31 || d2<1)) || (m2 == 6 && (d2>30 || d2<1)) || (m2 == 7 && (d2>31 || d2<1)) || (m2 == 8 && (d2>31 || d2<1)) || (m2 == 9 && (d2>30 || d2<1)) || (m2 == 10 && (d2>31 || d2<1)) || (m2 == 11 && (d2>30 || d2<1)) || (m2 == 12 && (d2>31 || d2<1)) || y2<2000 || m2>12 || m2<1 || 
     y2>y1 || (y1 == y2 && m2>m1) || (y1 == y2 && m1 == m2 && d2>d1)) 
     ... 
     x++; 

あなたの論理は間違って、冗長です。 は、1日未満の場合はに1回のみチェックする必要があります。少なくとも20回チェックしています。次に別の機能で20回もう一度チェックします。あなたはd2のためにそれを繰り返す。これにより、コードの読み取りが不可能になり、エラーが発生しやすくなります。

また、変数を初期化していません。 xの開始値は未定義です。

i=0; 
x=i++; 

あなたはx = 1としてこれを書き換えることができます:int x = 0;i = 0;

後で、持って入れてください。しかし、あなたはおそらく、あなたが休日のためにチェックしているようだ。ここx++

を書くことを意味:

else if((
    d == 1 && m == 1) || 
    (d == 1 && m == 5) || 
    (d == 8 && m == 5) || 
    (d == 5 && m == 7) || 
    (d == 6 && m == 7) || 
    (d == 28 && m == 9) || 
    (d == 28 && m == 10) || 
    (d == 17 && m == 11) || 
    (d == 24 && m == 12) || 
    (d == 25 && m == 12) || 
    (d == 26 && m == 12) || 

コーディングのこのタイプは間違っていないが、それはどちらかの実用的ではありません。私は構造で休日を置く:

struct holidays_t 
{ 
    int day, month; 
}; 

struct holidays_t holidays[] = { 
    { 1 , 1 }, 
    { 1 , 5 }, 
    ... 
}; 

次にループholidays配列によって日付が一致するかどうかを確認します。まだ構造を学習していない場合は、日と月を2つの異なる配列に入れます。例:

int holiday_days[]={1,1,...}; 
int holiday_months[]={1,5,...}; 

曜日の式が間違っています。あなたはそれを修正する必要があります。

#include <stdio.h> 
#include <math.h> 

int is_leap_year(int y) 
{ 
    return (y % 4) == 0 && y % 100 != 0 || (y % 400 == 0 && y != 4000); 
} 

int get_days_in_month(int year, int month) 
{ 
    const int days_in_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 
    if(month >= 1 && month <= 12) 
    { 
     int days = days_in_month[month - 1]; 
     if(month == 2 && is_leap_year(year)) 
      days++; 
     return days; 
    } 
    return 0; 
} 

int is_date_valid(int year, int month, int day) 
{ 
    if(get_days_in_month(year, month) == 0) return 0; 
    return day >= 1 && day <= get_days_in_month(year, month); 
} 

//this is wrong: *************************************************** 
int get_weekday(int y, int m, int d) 
{ 
    int h = (d + floor(((m + 1) * 26)/10) + y + floor(y/4) + 6 * floor(y/100) + floor(y/400)); 
    int weekday = h % 7; 
    return weekday; 
} 

struct holidays_t 
{ 
    int day, month; 
}; 

int is_holiday(int m, int d) 
{ 
    const struct holidays_t holidays[] = { 
     { 1 , 1 }, 
     { 1 , 5 }, 
     { 8 , 5 }, 
     { 5 , 7 }, 
     { 6 , 7 }, 
     { 28, 9 }, 
     { 28, 10 }, 
     { 17, 11 }, 
     { 24, 12 }, 
     { 25, 12 }, 
     { 26, 12 }, 
    }; 

    int count = sizeof(holidays)/sizeof(holidays[0]); 

    int i; 
    for(i = 0; i < count; i++) 
     if(holidays[i].month == m && holidays[i].day == d) 
      return 1; 
    return 0; 
} 

int CountWorkDays(int y1, int m1, int d1, int y2, int m2, int d2, int *ptr) 
{ 
    int count = 0; 
    *ptr = 0; 
    if(!is_date_valid(y1, m1, d1)) return 0; 
    if(!is_date_valid(y2, m2, d2)) return 0; 

    int y, m, d; 
    for(y = y1; y <= y2; y++) 
    { 
     int month_start = 1; 
     int month_end = 12; 

     if(y == y1) month_start = m1; 
     if(y == y2) month_end = m2; 

     for(m = month_start; m <= month_end; m++) 
     { 
      int day_start = 1; 
      int day_end = get_days_in_month(y, m); 

      if(y == y1 && m == m1) day_start = d1; 
      if(y == y2 && m == m2) day_end = d2; 

      for(d = day_start; d <= day_end; d++) 
      { 
       int test = 0; 
       if(is_holiday(m, d)) 
       { 
        test = 1; 
        printf("holiday %d %d %d\n", y, m, d); 
       } 

       int weekday = get_weekday(y, m, d); 
       if(weekday == 0 || weekday == 6) 
       { 
        test = 1; 
        printf("weekend %d %d %d %s\n", y, m, d, (weekday == 0) ? "sunday" : "staurday"); 
       } 

       if(!test) 
       { 
        count++; 
       } 
      } 
     } 
    } 

    *ptr = count; 

    //return success 
    return 1; 
} 

int main() 
{ 
    int count = 0; 
    CountWorkDays(2016, 1, 1, 2016, 12, 31, &count); 
    printf("count %d\n", count); 
    return 0; 
} 
+0

ありがとう、私はそれを修正しましたが、私は 'cnt'(2日間の作業日数)を把握する方法をまだ分かりません。なぜなら、whileに' next_day'関数がある前にサイクルの中に何を入れるべきかわからないので、私は 'if(!is_date_valid ...)'をチェックして何を? – anonym

+0

あなたの公式は間違っています。 –

+0

私はちょうど 'cnt'をカウントするためにどのサイクルを使うべきか知りたいと思っていました – anonym

関連する問題