1

私は単純なカレンダークラスを書いています。operator++カレンダーを次の月に移動するために使用するためにオーバーロードしようとしています。ただし、翌月の開始日を見つけるアルゴリズムは正しくありません。

calendar calendar::operator ++(int)
{
   int hold;
   calendar cal = *this;

   month++;
   if (month > December)
   {
      month = January;
      year++;
      if (year == 0)
         year++;
   }
   previousStartDay = startDay;
   startDay = nextStartDay;
   nextStartDay = findNextStartDay();
   return cal;
}

int calendar::findNextStartDay() const
{
   int monthLength,
       day = startDay;

   monthLength = findMonthLength(false);
   monthLength -= 28;
   day += monthLength;
   if (day > Saturday)
      day -= Saturday;
   return day;
}

1 月は 0、12 月は 11、日曜日は 0、土曜日は 6 と定義されます。startDay、previousStartDay、nextStartDay、month、および year はすべてプライベート クラス変数です。

これを 2013 年にテストすると、日付は 3 月まで正確です。その時点で、次の開始日が月曜日ではなく火曜日になります。

私もこれを試しました:

int calendar::findNextStartDay() const
{
   int monthLength,
       day = startDay;

   monthLength = findMonthLength(false);
   monthLength -= 28;
   day -= monthLength;
   if (day < Sunday)
      day += Saturday;
   return day;
}

ただし、同じ結果も得られます。

編集:

うるう年を考慮しています。findMonthLength()これがそうであるかどうかを判断するための私のコードです。

if ((!(year % 4) && (year % 100)) || !(year % 400))
   monthLength = 29;
else
   monthLength = 28;
4

4 に答える 4

3

問題分析

今が 3 月で、正しい開始日 (金曜日、5 日) があるとします。

findNextStartDayアルゴリズムは3 ( 31-28 monthlength) に等しいと判断し、その場合、日は 2 (8 - 6) になり、月曜日 (1) ではなく火曜日 (2) になります...

findNextStartDayアルゴリズム ( の最初のバージョン)を実行して、これが間違っている理由を見てみましょう。

1 月: 31-28 = 3、day = 2 (火曜日) + 3 = 5 (金曜日)、これは 2 月の正しい開始日です。

2 月: 28 - 28 = 0、日 = 5 (金曜日) + 0 = 5 (金曜日)、これは 3 月の正しい開始日です。

3 月: 31-28 = 3、day = 5 (金曜日) + 3 - 6 (土曜日) = 2 (火曜日) で、4 月の開始日が間違っています。

バグの説明

問題は、土曜日を差し引いて結果がオーバーフローする (土曜日よりも多い) 場合、カウントから 1 日を残すことになります (つまり、必要な日よりも 1 日少なく引くことになります)。

で終わるケースを考えてみてくださいday == 7。日曜日 (土曜日よりも 1 つ多い - 循環的に増加) が必要な場合は、6 ではなく 7 を削除する必要があります。そうしないと、月曜日になります!

エラーは循環インクリメントにあります。正しいアルゴリズムでは、6 を超える 1 (つまり 7) は 0 に戻らなければならず、6 を超える 2 (つまり 8) は 1 に戻らなければなりません。

あなたのアルゴリズムでは、6 (つまり 7) を超える 1 は 1 に戻り、悪い 0 (日曜日) を除外し、この場合になるたびに 1 つの曜日が消えます。

差し引くSaturday + 1と、「平日オーバーフロー」の場合に翌月の正しい日が得られます。

バグ修正

つまり、次の行を変更します。

day -= Saturday;

day -= (Saturday + 1);

ただし、コードを見直してアルゴリズムのよりクリーンなバージョンにすることを検討してください。

小さなヒントは、モジュロ演算子を使用して循環加算を行うことです。

day = ((day + monthlength) % (Saturday + 1))
于 2013-05-02T20:48:13.827 に答える
2

boost は、いくつかの良いを提供します。boost::gregorianここでは、例の 1 つに基づいて実装しました。このコードは、年、月を取り、翌月の最初の日付と曜日を出力します。

#include <cstdlib>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
#include <stdio.h>

int main(int argc, char** argv) {

    using namespace boost::gregorian;

    greg_year year(1400);
    greg_month month(1);

    // get a month and a year from the user
    try {
      int y, m;
      std::cout << "   Enter Year(ex: 2002): ";
      std::cin >> y;
      year = greg_year(y);
      std::cout << "   Enter Month(1..12): ";
      std::cin >> m;
      month = greg_month(m);
    }
    catch(bad_year by) {
      std::cout << "Invalid Year Entered: " << by.what() << '\n'
        << "Using minimum values for month and year." << std::endl;
    }
    catch(bad_month bm) {
      std::cout << "Invalid Month Entered" << bm.what() << '\n'
        << "Using minimum value for month. " << std::endl;
    }

    // create date and add one day to the end of month
    date d(year, month, 1);
    d=(year,month,d.end_of_month());
    date_duration dd(1);
    d += dd;
    // print date
    std::cout << d << " " << d.day_of_week() << std::endl;
    return 0;
}

出力例:

年を入力してください (例: 2002): 2013

月を入力してください (1..12): 3

2013-04-01 月

RUN SUCCESSFUL (合計時間: 6 秒)


使用std::vector:

boost::gregorian::date d1(2013,boost::gregorian::Jan,31);
boost::gregorian::date d2(2013,boost::gregorian::Feb,28);
boost::gregorian::date d3(2013,boost::gregorian::Mar,31);

std::vector<boost::gregorian::date > v;
v.push_back(d1);
v.push_back(d2);
v.push_back(d3);

boost::gregorian::date_duration duration(1);

for(std::vector<boost::gregorian::date >::iterator it=v.begin();it!=v.end();it++){
    *it+=duration;
    std::cout << *it <<" "<< (*it).day_of_week() << std::endl;
}
于 2013-05-02T21:08:17.783 に答える