문제

Oracle Function Add_months를 사용하여 날짜를 x 개월 씩 증가시키는 코드가 있습니다.

이제 C / C ++ 기능에서 동일한 논리를 다시 구현해야합니다. 내가 들어가기를 원하지 않는 이유 때문에 나는 새로운 날짜를 얻기 위해 Oracle에 쿼리를 발행 할 수 없습니다.

Time_T에 x 개월을 추가하는 간단하고 신뢰할 수있는 방법을 아는 사람이 있습니까? 계산 유형의 일부 예는 다음과 같습니다.

30/01/2009 + 1 개월 = 28/02/2009
31/01/2009 + 1 개월 = 28/02/2009
27/02/2009 + 1 개월 = 27/03/2009
28/02/2009 + 1 개월 = 31/03/2009
31/01/2009 + 50 개월 = 31/03/2013

도움이 되었습니까?

해결책

방법 addmonths_oraclestyle 필요한 것을합니다.

아마도 당신은 isleapyear와 getdaysinmonth를 일부 사서 방법으로 대체하고 싶을 것입니다.

#include <ctime>
#include <assert.h>

bool IsLeapYear(int year) 
{
    if (year % 4 != 0) return false;
    if (year % 400 == 0) return true;
    if (year % 100 == 0) return false;
    return true;
}

int daysInMonths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int GetDaysInMonth(int year, int month)
{
    assert(month >= 0);
    assert(month < 12);

    int days = daysInMonths[month];

    if (month == 1 && IsLeapYear(year)) // February of a leap year
        days += 1;

    return days;
}

tm AddMonths_OracleStyle(const tm &d, int months)
{
    bool isLastDayInMonth = d.tm_mday == GetDaysInMonth(d.tm_year, d.tm_mon);

    int year = d.tm_year + months / 12;
    int month = d.tm_mon + months % 12;

    if (month > 11)
    {
        year += 1;
        month -= 12;
    }

    int day;

    if (isLastDayInMonth)
        day = GetDaysInMonth(year, month); // Last day of month maps to last day of result month
    else
        day = std::min(d.tm_mday, GetDaysInMonth(year, month));

    tm result = tm();

    result.tm_year = year;
    result.tm_mon = month;
    result.tm_mday = day;

    result.tm_hour = d.tm_hour;
    result.tm_min = d.tm_min;
    result.tm_sec = d.tm_sec;

    return result;
}

time_t AddMonths_OracleStyle(const time_t &date, int months)
{
    tm d = tm();

    localtime_s(&d, &date);

    tm result = AddMonths_OracleStyle(d, months);

    return mktime(&result);
}

다른 팁

당신이 사용할 수있는 boost.gregoriandate 이것을 위해.

보다 구체적으로, 올바른 것을 추가하여 달을 결정하십시오. date_duration, 그런 다음 사용합니다 end_of_month_day() 날짜 알고리즘에서

전환하다 time_t 에게 struct tm, X를 한 달에 추가하고, 12 개월에서 몇 년 동안 몇 개월을 추가하고, 뒤로 변환하십시오. tm.tm_mon은 int이며 32000 개월 이상을 추가하는 것은 문제가되지 않아야합니다.

편집] 12 개월에서 29/02/29/02/29/02/29/02를 추가하는 것과 같이 더 어려운 케이스에 도달하면 일치하는 Oracle이 까다로울 수 있습니다. 2009 년 1 월 3 일과 2008 년 28 월 28 일 모두 합리적입니다.

진짜 A에 대한 새로운 답변 진짜 오래된 질문!

사용 이 무료 및 오픈 소스 라이브러리, 및 C ++ 14 컴파일러 (예 : Clang) 이제 다음에 쓸 수 있습니다.

#include "date.h"

constexpr
date::year_month_day
add(date::year_month_day ymd, date::months m) noexcept
{
    using namespace date;
    auto was_last = ymd == ymd.year()/ymd.month()/last;
    ymd = ymd + m;
    if (!ymd.ok() || was_last)
        ymd = ymd.year()/ymd.month()/last;
    return ymd;
}

int
main()
{
    using namespace date;
    static_assert(add(30_d/01/2009, months{ 1}) == 28_d/02/2009, "");
    static_assert(add(31_d/01/2009, months{ 1}) == 28_d/02/2009, "");
    static_assert(add(27_d/02/2009, months{ 1}) == 27_d/03/2009, "");
    static_assert(add(28_d/02/2009, months{ 1}) == 31_d/03/2009, "");
    static_assert(add(31_d/01/2009, months{50}) == 31_d/03/2013, "");
}

그리고 그것은 컴파일합니다.

실제 코드와 OP의 의사 코드 간의 현저한 유사성에 유의하십시오.

30/01/2009 + 1 개월 = 28/02/2009
31/01/2009 + 1 개월 = 28/02/2009
27/02/2009 + 1 개월 = 27/03/2009
28/02/2009 + 1 개월 = 31/03/2009
31/01/2009 + 50 개월 = 31/03/2013

또한 컴파일 타임 정보 안에 컴파일 타임 정보로 이어집니다 밖으로.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top