我有一些代码,使用Oracle功能add_months增加一个新的X个月。

我现在需要重新实现同样的逻辑,在C/C++的功能。原因我不想要的/需要进入我可以不是询问oracle以获得新的日期。

任何人都不会知道的简单和可靠的方式增加数X个月到一time_t?一些实例种类型的计算如下表所示。

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添加到月份,添加月份&gt; 12年,转回来。 tm.tm_mon是一个int,添加32000+个月应该不是问题。

[edit]你可能会发现,一旦你遇到更难的情况,匹配甲骨文就很棘手,比如在2002年2月29日增加12个月。 2009年1月3日和28/02/2008都是合理的。

真的 新答案 真的 旧的问题!

使用 这一免费的开放源图书馆, 和一个C++14compiler(例如铛)现在,我可以写这样的:

#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, "");
}

它编译。

注意到显着的相似之间的实际代码,以及运的伪码:

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