I am using HowardHinnant date library in my project. I want to get the exact datetime before n months.
For Example : "2016-12-17 18:21:26" is current datetime and, i want to know the datetime of 13 months before. It should output "2015-11-17 18:21:26".
/*
* This function will return the current date in year_month_day format
*/
auto currentDate() {
auto currentTime = std::chrono::system_clock::now();
date::year_month_day currentDate = date::floor<date::days>(currentTime);
return currentDate;
}
/*
* This function will find the date before (n) months
*/
template <typename T>
auto oldDate(T monthsNum) {
auto currentDate = currentDate();
auto yearCurrentDate = (int)currentDate.year();
auto monthCurrentDate = currentDate.month();
auto dayCurrentDate = currentDate.day();
auto yearNum = monthsNum/12;
auto yearEndDate = yearCurrentDate - yearNum;
auto monthNum = monthsNum%12;
auto monthEndDate = monthCurrentDate;
while(monthNum) {
monthEndDate--;
}
if(monthEndDate > monthCurrentDate) {
yearEndDate--;
}
date::year_month_day endDate = date::year{yearEndDate}/monthEndDate;
return endDate;
}
My function oldDate()
will return the date which was n
months before. But i am not able to get the time.
Instead of
currentDate()
, create acurrentTime
which returns asys_seconds
(time with seconds precision):Now
oldDate
can callcurrentTime
instead ofcurrentDate
and in that way know and preserve the time-of-day.oldDate
should take as a parameterdate::months
which is astd::chrono::duration
with a precision of months. Here's what it could look like (description afterward):The
using namespace date
is handy otherwise you're going to havedate::
just all over the place.First get the time from
currentTime()
. This is astd::chrono::time_point<system_clock, seconds>
, or a count of seconds since 1970-01-01 UTC.Then truncate this count of seconds into a count of days with
floor<days>()
. This is astd::chrono::time_point<system_clock, days>
.One can think of
sd
as a time point to the first instant of the day (in UTC). So if you subtractsd
fromtime
you get astd::chrono::duration
representing the time-of-day. The precision is going to be thecommon_type
of the two precisions you're subtracting (seconds
).To do the month arithmetic, you need to switch the type of
sd
fromsys_days
(atime_point
) toyear_month_day
(a calendar type). Once you have typeyear_month_day
, you can just subtract themonthsNum
from it, yielding anotheryear_month_day
(stored inymd
above).You can check if this resulted in a valid date or not with
.ok()
. If it is an invalid date, that means you overflowed the days field of theyear_month_day
. I see in the comments that if this happens, you want the last day of the month. So just extract theyear
andmonth
and uselast
to resetymd
to the last day of the month for that year.Finally convert the
ymd
back into asys_days
(time_point
withdays
precision) and add thetime_of_day
back to it.The result is
sys_seconds
(time_point
withseconds
precision).I just ran this with this driver:
And the output was:
Convenience link to documentation.