在C / C ++中添加1个月到time_t的简单方法

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

我现在需要在C / C ++函数中重新实现相同的逻辑。 由于我不想/需要进入的原因,我不能简单地向oracle发出查询以获取新日期。

有没有人知道在time_t中添加X个月的简单可靠的方法? 计算类型的一些示例如下所示。

30/01/2009 + 1个月= 2009年2月28日
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  #include  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+个月应该不是问题。

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

一个非常古老的问题的真正新答案!

使用这个免费的开源库和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个月= 2009年2月28日
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

另请注意,编译时信息会导致编译时信息输出