简单的方法来增加1个月至一time_t C/C++
题
我有一些代码,使用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
还注意到,编纂时的信息 在 导致汇编时的信息 出来.