代码之家  ›  专栏  ›  技术社区  ›  Glen

在C/C中向时间添加1个月的简单方法++

  •  6
  • Glen  · 技术社区  · 16 年前

    我有一些代码使用Oracle函数add_months将日期增加X个月。

    有没有人知道一种简单可靠的方法,可以将X个月数加到时间上? 计算类型的一些示例如下所示。


    2009年1月31日+1个月=2009年2月28日


    2009年1月31日+50个月=2013年3月31日

    4 回复  |  直到 9 年前
        1
  •  6
  •   Pieter    16 年前

    你可以用 Boost.GregorianDate

    更具体地说,通过添加正确的 date_duration ,然后使用 end_of_month_day() 从日期算法

        2
  •  5
  •   MSalters    16 年前

    time_t struct tm ,将X添加到月份,添加月份>12年,换回来。tm.tm_mon是一个整数,添加32000多个月应该不会有问题。

    [编辑]您可能会发现,一旦遇到更困难的情况,比如在2008年2月29日之前增加12个月,匹配Oracle是一件棘手的事情。2009年3月1日和2008年2月28日都是合理的。

        3
  •  4
  •   Howard Hinnant    9 年前

    真正地 新答案 真正地 老问题!

    this free and open source library

    #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的伪代码之间有着惊人的相似性:

    2009年1月30日+1个月=2009年2月28日

    2009年2月27日+1个月=2009年3月27日
    2009年2月28日+1个月=2009年3月31日
    2009年1月31日+50个月=2013年3月31日

    还要注意编译时信息 .

        4
  •  3
  •   Konstantin Spirin    16 年前

    方法 AddMonths\u 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);
    }