2

This is how im generating my date i want to add 1 year to it. Thanks in advance.

char tmpbuf[128];
time_t ltime;
struct tm *today;
stringstream reD;
string todayDate;
time( &ltime );
today = localtime( &ltime );
strftime( tmpbuf, 128,"%Y-%m-%d_%H:%M:%S", today );
reD << tmpbuf;
reD >> todayDate;
boost::replace_all(todayDate, "_", " ");
cout << todayDate << endl;

OK ive decided to go with boost since it will be easier to add days, so 2 examples i need one to add 1 year, and one to add 14 days, heres what i have so fare

 #include "boost/date_time.hpp"
 #include "boost/date_time/local_time/local_time.hpp"

 using namespace boost::posix_time;
 using namespace boost::local_time;

 int main(){
    local_date_time t = local_sec_clock::local_time(time_zone_ptr());
    local_time_facet* lf(new local_time_facet("%Y-%m-%d_%H:%M:%S"));
    std::cout.imbue(std::locale(std::cout.getloc(), lf));
    std::cout << t << std::endl;
    return 0;
 }

Edit putting time into string

 stringstream reD;
 reD.imbue(locale(reD.getloc(), lf));
 reD << t;
 bthis = reD.str();
 cout << bthis << endl;
user1054513
  • 605
  • 3
  • 13
  • 24

4 Answers4

5

If you're using C++, I highly recommend boost::date_time to take the leg-work out of this.

Moo-Juice
  • 38,257
  • 10
  • 78
  • 128
4

There is no such thing as "adding a year".

Let us suppose that you go into incrementing the year by 1, after all, that is what you are aiming for.

Unfortunately, there are some inconsistencies in the way we deal with the time:

  • leap years: if you are on February 29th, 2008, what does adding a year mean ? February 28th, 2009 or March 1st, 2009 ? (Hint: changing the month is very confusing for the user of a calendar)

  • leap seconds: on June 30th or December 31th, a second or two might be added to the last minute, making that minute 61 or 62 seconds. (Hint: once again, changing the day is confusing)

  • special events: like the calendar re-adjustment that occurred in 1582, where Thursday, October 4, 1582 was followed by Friday, October 15, 1582, resulting in a full 10 days loss.

The problem here, is not really in "adding" a year, you can always choose to round down (preferably when end-users are involved) or up. The real problem is that if you follow this reasoning, you unfortunately lose the symmetry between adding and removing a year:

  • original: February 29th, 2008
  • + 1 year: March 1st, 2009 (rounding up)
  • - 1 year: March 1st, 2008

or by adding 4 years in several consecutive leaps:

  • original: February 29th, 2008
  • + 2 years: February 28th, 2010 (rounding down)
  • + 2 years: February 28th, 2012

Oups!

The mathematical solution to this is to simply evaluate the year duration in terms of seconds, Let's ask Wolfram about it: 3.154 × 10^7 seconds.

However, it may be quite confusing for the user.

And finally, the last solution is that whenever you make computations based on dates and duration, you save the original date away, compute the durations on their own, and then adjust the "displayed" date.

This way, you will be both mathematically correct (ie, respect symmetry and associativity) and behave intuitively for end users.

class MyTime {
  ...
private:
  tm _origin;
  tm _deviation;
};

However it is more work... so you have to decide on your scheme by yourself, depending on your application needs.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
3

I agree about using boost::date_time, however, the solution here is quite easy.

today->tm_year++;

Although, if you happen to call localtime again, the value will be overwritten, so you should make a copy. Make today an instance instead of a pointer, and dereference the return value of localtime like this:

today = *localtime( &ltime );

You'll have to take into account certain anomalies, like incrementing a year from February 29th on a leap year.

Edit: I see you've decided to use boost::date_time after all. This makes things much simpler. Here's how you add a year:

t += boost::gregorian::years(1);

And here's how you add 14 days:

t += boost::gregorian::days(14);

Or

t += boost::gregorian::weeks(2);
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • I am wondering if that would work for `5 October 1582`? May depend on your locale. – Martin York Dec 09 '11 at 19:35
  • @LokiAstari: yes, the tricky part about manipulating dates directly is that they are just so... fickle. Adding year is near easy, adding a month is about meaningless :x – Matthieu M. Dec 09 '11 at 19:47
  • So your saying it wont increment 1 year if its feb 29th? – user1054513 Dec 09 '11 at 20:08
  • 1
    @user1054513: It will increment the year, but it will give you an invalid date, since february 29th of a non-leap-year does not exist. [Here's the structure](http://en.cppreference.com/w/cpp/chrono/c/tm), so you know what you need to check. – Benjamin Lindley Dec 09 '11 at 20:14
  • i've added new example for boost above, just need to figure out how to increment 1 year and another increment of 14 days. – user1054513 Dec 09 '11 at 20:23
  • excellent and this will take care of leap year and any other date time dilemmas? – user1054513 Dec 09 '11 at 20:46
  • @user1054513: Yes. At least it's meant to. If it doesn't, then it's a bug, and should be reported. Unlike the other method which makes no promises about complicated issues like that. – Benjamin Lindley Dec 09 '11 at 20:48
  • one more question, trying to get the t variable into a string i tried stringstream ss then ss.str() but it gives date 2012-Dec-09 how do i get the t var into a string var – user1054513 Dec 09 '11 at 21:18
-1

Oh good grief, you C++ people :)

// compare June 15 2018 - 2017 to 2017 - 2016
struct tm y1_tm, y2_tm, y3_tm;
time_t y1716, y1817;  // differences

y1_tm.tm_sec = 0;  // 2016
y1_tm.tm_min = 0;
y1_tm.tm_hour = 0;
y1_tm.tm_mon = 6;
y1_tm.tm_mday = 15;
y1_tm.tm_year = 2016 - 1900;
y1_tm.tm_mday = 1;

y2_tm.tm_sec = 0;  // 2017
y2_tm.tm_min = 0;
y2_tm.tm_hour = 0;
y2_tm.tm_mon = 6;
y2_tm.tm_mday = 15;
y2_tm.tm_year = 2017 - 1900;
y2_tm.tm_mday = 1;

y3_tm.tm_sec = 0;  // 2018
y3_tm.tm_min = 0;
y3_tm.tm_hour = 0;
y3_tm.tm_mon = 6;
y3_tm.tm_mday = 15;
y3_tm.tm_year = 2018 - 1900;
y3_tm.tm_mday = 1;

y1716 = mktime(&y2_tm) - mktime(&y1_tm);  // 2017 - 2016
y1817 = mktime(&y3_tm) - mktime(&y2_tm);  // 2018 - 2017

Both subtractions yield 31536000 seconds. Add that to a time_t for 1 year.

Alan Corey
  • 577
  • 6
  • 10
  • This "answer" is the same as [Martin York's comment from 7 years ago](https://stackoverflow.com/questions/8450569/c-add-1-year-to-date#comment10446274_8450569), except that he disclosed that it doesn't work on leap years, and you overlooked that. – Ben Voigt Jul 30 '18 at 04:57
  • I didn't overlook it, the data I needed it for starts July 2016. 2016 - 2015 is 31622400 instead. Leap days probably do something similar. But I construct the struct tms by plugging in values, convert to time_t and subtract. Almost everything is visible. – Alan Corey Jul 30 '18 at 12:56
  • My application is to offset and superimpose years of temperature data to feed to Gnuplot. I didn't know if a year was considered 365 or 365.25 days, it's 365 but 364 on leap years, just like reality. An error might have made my daytime peaks line up with nighttime lows and stick out like a sore thumb. I needed to know which way it worked. A leap year is 86400 seconds shorter, exactly one day. There's no averaging. – Alan Corey Jul 30 '18 at 13:05
  • Leap years are a day longer, not shorter. I was past my 5 minutes to edit that in. Making everything visible is more like a mathematical proof. Mktime may do something funky and hidden but I don't think so. – Alan Corey Jul 30 '18 at 13:15