0

I am trying to add a certain amount of days to a date. I've looked at examples such as Arithmetics on calendar dates in C or C++ (add N days to given date), but I'm still coming across this problem.

If the num_of_days is a large number, let's say 100, and the beginning day is expire_time.tm_mday = 10. The final day is 110. So when I do mktime(&expire_time); it doesn't convert this day to a valid time; the expire_time.tm_mday still is equal to 110. I want it to add like 3 months on and be a day between 1-31. Why is this?

void add_num_of_days(int* month, int* day, int* year, int num_of_days) 
{
   struct tm expire_time = {};
   int date_to_days;
   expire_time.tm_year = *year - 1900;
   expire_time.tm_mon = *month - 1;
   expire_time.tm_mday = *day;

   //expire_time.tm_mday = 15;
   //num_of_days = 40;
   expire_time.tm_mday += num_of_days;

   mktime(&expire_time);

   //expire_time.tm_mday = 55! (NOT WHAT I WANT).
   *day = expire_time.tm_mday;
   *month = expire_time.tm_mon + 1;
   *year = expire_time.tm_year + 1900;
}

The calling code:

month1 = atoi(start_date.Mid(0, 2)) + 1;
day1 = atoi(start_date.Mid(2, 2));
year1 = atoi(start_date.Mid(4)) + 1900;
//Add the number of days the license 
//period is for to the start date.
add_num_of_days(&month1, &day1, &year1, atoi(num_of_days));

Start date:

//First 32 bits is for the starting date.
CString start_date = get_start_date(byte_array.Mid(0, 32));
//Example start_date would be 01152016 for Jan 15th 2016.
Community
  • 1
  • 1
Nolemonpledge
  • 139
  • 1
  • 2
  • 11

1 Answers1

1

You are not checking the return value of mktime(&expire_time);. According to the documentation it returns -1 if calendar time cannot be represented, so in that case your input parameter is unchanged.

To avoid such problems you may change your procedure to:

bool add_num_of_days(int* month, int* day, int* year, int num_of_days) 
{
   struct tm expire_time = {};
   int date_to_days;
   expire_time.tm_year = *year - 1900;
   expire_time.tm_mon = *month - 1;
   expire_time.tm_mday = *day;

   expire_time.tm_mday += num_of_days;

   if (-1 == mktime(&expire_time))
   {
      return false;
   }

   *day = expire_time.tm_mday;
   *month = expire_time.tm_mon + 1;
   *year = expire_time.tm_year + 1900;
   return true;
}

And then checking the return value of your function on invocation.


And, now let's get to the reason why the mktime says that it can't convert your date.

When you are using 01152016 as your input date, the year in the date is 2016. However, when you are converting from the string to an int, you add additional 1900 to it (year1 = atoi(start_date.Mid(4)) + 1900;), making the date equal to 3916. Apparently, that is too far in the future than mktime can handle (my guess would be, that it can't represent your date within the size limits of time_t).

Note, even though you subtract the year 1900 in your function, to mktime the year is still equal to 3916, since tm.tm_year is defined as "years since 1900", so when you have 2016 years after the year 1900, it is still equal to 3916.

Algirdas Preidžius
  • 1,769
  • 3
  • 14
  • 17
  • I was just looking into this being the problem. So thank you! – Nolemonpledge Jan 15 '16 at 15:56
  • Well, I do subtract 1900 from the year before I do mktime(&expire_time) so there must be some other reason, so I will keep looking. – Nolemonpledge Jan 15 '16 at 15:59
  • @user3529319 The reason is still the same. Please look at the example in the `mktime`s documentation that I linked to, since [tm.tm_year](http://www.cplusplus.com/reference/ctime/tm/) is defined as "years since 1900", so your effective year value, that is passed to the `mktime` is unchanged (=3916). I will edit the answer. to account for that. – Algirdas Preidžius Jan 15 '16 at 16:05
  • time_t is a signed 32 bit in most cases, which means the last year that can be represented by it is 2038. (https://en.wikipedia.org/wiki/Year_2038_problem) Most systems are moving to a 64 bit int though, which will roll over in about 292 billion years. – Rob K Jan 15 '16 at 16:23
  • @RobK I tried to check if the size of `time_t` is clearly defined before posting this answer, but, apparently, it isn't. And, on my machine, size of `time_t` is 8 bytes, but `mktime` still returned an error in the use case posted by OP. – Algirdas Preidžius Jan 15 '16 at 16:27
  • I suppose I should have said "in most historical cases". The size of `time_t` is usually controlled by `#ifdef`s which depend on the platform and compiler you're targeting and your own `#defines`. For instance Windows is now using `__int64` for `time_t` unless you `#define _USE_32BIT_TIME_T` and it has 32 and 64 bit versions of all the time functions. Cf. http://stackoverflow.com/questions/471248/what-is-ultimately-a-time-t-typedef-to for a more complete discussion. – Rob K Jan 15 '16 at 16:55