2013-05-02 2 views
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월는 토요일 6 startDay를, previousStartDay, nextStartDay 년, 월, 모든 개인 클래스 변수가

I 2013이 테스트를하는 경우, 일요일 0, 12 월 11, 0으로 정의된다 , 날짜는 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; 
+0

2012 년 3 월의 목요일은 목요일 이었습니까? –

+0

결과가 잘못되었다고합니다. 2 월은 이상한 윤년 규칙이있는 달입니다. hmmm –

+0

죄송합니다. 2013 년 죄송합니다. 지금 수정 중입니다 ... – kennycoc

답변

3

문제점 분석

은의 우리가 월에 있고 올바른 시작 하루 가정하자 (금요일, 5). (2) 대신 월요일 (1) ...

하자 화요일 -

찾을 수 귀하의 findNextStartDay 알고리즘은 monthlength 같음 3 (31-28), 다음 날 2 (6 ~ 8)입니다

1월 :이 (findNextStartDay의 첫 번째 버전은) 알고리즘을 실행하여 잘못된 이유를 볼 31-28 = 3 일 = 2 일 (화) + 3 = 5 올바른 시작 날짜입니다 (금) 2 월.

2 월 : 28 - 28 = 0, 일 = 5 (금) +0 = 5 (금), 이는 3 월의 올바른 시작 날짜입니다.

: 31-28 = 3, 일 = 5 (금) + 3 - 6 (토요일) = 2 (화요일)로 4 월의 시작일이 잘못되었습니다.

버그 설명

문제는 당신이 (토요일보다 더) 오버 플로우 결과 토요일을 뺄 때, 당신은 (즉, 카운트에서 하루 떠나는 것입니다 : 당신은 당신이 원하는 것보다 일일 이하 빼기).

day == 7으로 끝나는 경우를 생각해보십시오. 일요일 (토요일보다 순환 적으로 증가한 것보다 많음)을 원한다면, 6이 아닌 7을 제거해야합니다. 그렇지 않으면 월요일에 도착합니다!

오류는 순환 증분으로 표시됩니다. 정확한 알고리즘 1에서 6 (즉 7)은 0으로 돌아 가야하고, 6을 넘어 2는 1로 돌아 가야합니다 (등).

귀하의 알고리즘에서 6 (즉 7)을 초과하는 1은 1로 돌아가고, 가난한 0 (일요일)은 제외하고이 경우에 끝날 때마다 한 요일을 사라지게 만듭니다.

Saturday + 1을 뺍니다. "weekday overflow"의 경우 다음 달의 올바른 날을 얻습니다.

day -= Saturday; 

day -= (Saturday + 1); 

에하지만, 알고리즘의 깨끗한 버전으로 코드를 검토 고려하시기 바랍니다 :

한마디로

버그 수정이 줄을 변경!

day = ((day + monthlength) % (Saturday + 1)) 
0

나는 이번 달 29, 28 일 우선은 이번 달 if 문을 만들 수 있습니다 (올해가 윤년의 년이 아닌 경우 따라 다름) 가질 수 있기 때문에 문제가 월에 생각합니다. mod 연산자를 사용하여 연도가 bissextile인지 알아낼 수 있습니다. if : year % 4 =! 2 월 2 일은 28 일, 그 외에는 29 일이 있습니다. 희망이 도움이 될 것입니다!

+1

많은 사람들이 같은 실수를 저지르기는하지만 윤년 계산법은 잘못되었습니다. https://en.wikipedia.org/wiki/Leap_year – syam

+0

를 본다. 나는 당신의 코멘트를 보았다. 나는 무엇에 관한 글을 읽었다 : 그 해가 도약인지 아닌지를 어떻게 결정할 것인가? 그리고이 방법이 그 해에만 유효하다는 것을 안다. 44 BC 전에 (그레고리오 개혁을 가리킴).그러나 그것은 사실과 다르게 ... 처음에는 사람들이 "4 년에 한 번"이 의미하는 것을 이해하지 못했으며, 매 3 년마다 윤년이 있었던 기간 (45BC와 9BC 사이)이있었습니다. 어떤 도약이 전혀 없었던 기간 (8BC ~ 8AD 사이)이 뒤 따른다. –

+0

예, 100으로 나눌 수도 있지만 그렇지 않습니다. 400으로 나눌 수 없다면.하지만 이미 이것을 설명하고 있기 때문에 중요하지 않습니다. 내가 명확히하기 위해 원래 게시물을 업데이트했습니다. – kennycoc

1

부스트 좋은 examples의 당신 부부를 제공합니다

작은 팁은 원형 추가 할 모듈로 연산자를 사용하는 것입니다. 여기 예제를 기반으로 boost::gregorian을 구현했습니다.

#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; 
} 

예 출력 :이 코드는 년, 월, 인쇄 날짜와 다음 달 1 일의 요일 소요

년 (예 : 2002) : 입력 2013

을 성공적인 3

2013 4 월 - 01 월

RUN : 월 (1..12)를 입력 (총 시간 : 기가)

를 사용 6,

:

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; 
} 
+0

@kennycoc이 목표는 무엇입니까? – 4pie0

+0

이것은 좋은 일이지만 내 자신의 알고리즘을 사용하고 싶습니다. 만약 내가 프로그래밍을 시작하지 않았다면 아마 이것을 사용할 것입니다. 그러나 알고리즘을 먼저 찾지 않으면 더 빨리 배울 것이라고 생각합니다. – kennycoc

+0

만약 당신이 그것을 배우면 괜찮아 보인다. 그러나 나는 누군가와 나누고 자하는 프로젝트에서 자신의 것을 굴리지 말라. 용들이 있습니다 ... 당신은 정말로 C + +에서 부스트와 같은 단단한 라이브러리를 활용하거나 자바 스크립트에서 순간적으로 활용하고 싶습니다. – moodboom

0

이 코드는 당신에게 이전 달의 처음과 마지막 날을 제공합니다. 내 응용 프로그램에서 TDateTimePicker 구성 요소를 설정하는 데 사용했습니다.

Word Year, Month, Day; 
TDateTime datum_tdatetime = Date(); 

// first day of actual month 
datum_tdatetime.DecodeDate(&year, &month, &day); 
day = 1; 
datum_tdatetime = EncodeDate(year, month, day); 
// last day of previous month 
datum_tdatetime -= 1; 
// first day of previous month 
datum_tdatetime.DecodeDate(&year, &month, &day); 
day = 1; 
datum_tdatetime = EncodeDate(year, month, day); 
+0

무엇입니까? 유용한 정보를 알려주십시오. – Jonjie

관련 문제