Solved

# Adding a month to a current date

Posted on 2003-03-26
Medium Priority
492 Views

I have a CTimevar called dDepDate.  Can someone post a function to add 1 month (not just 31 days) to this date?  I don't feel like re-inventing the wheel.

Thanks,
Bryan
0
Question by:bfeddish
• 4
• 2
• 2

LVL 12

Expert Comment

ID: 8211765
Depends on what you mean by a 'month'. If you mean that from 15th of january you should get 15th of february?

so far so good...what about 31st of march? Should that be 31st of april? err.... let's rethink this a bit..

Your request is reasonable enough, however, the specification isn't complete. You need to decide what to do with dates when the next month doesn't have the date in question. What about 29th of january? Should it be 29th of february? That might work if the year is a leapyear, otherwise it won't.

One reasonable approach is to then always move it to the 'last day of the next month'. The question is then what to do when you want to add one more month:

30 january + 1 month == 30 february (too much) == 28/29th february.

Next month you get:

28/29th february + 1 month == ???

should it be 28/29th of march or should it be 30th of march (the original date)?

There are good reasons for selecting either choice and good reasons to avoid either, so which one you choose here is neither obvious nor "one solution fits all" it is very situation dependent. So the question is: why do you want this function? If you could tell us the reason we might be able to figure out which one is reasonable.

So, before we give you any algorithm I want you think over these issues and tell us which policy you want to select.

Simply saying you want a function that gets you next month is extremely poor specification.

Alf
0

LVL 12

Accepted Solution

Salte earned 750 total points
ID: 8212092
Assuming that a day within month is either a small number (mday <= 27) or that it always is the 'last day of the month' so that any day in month >= 28 is to be interpreted the last day of the month then the following function can add one month. I will assume the time is stored in a time_t variable and I will also assume that all dates are in the range 1st of jan 1970 midnight to some date in 2038. If the date gets close to 2038 I hope that time_t by that time has changed so that it can handle dates beyond 2038. If time_t is 64 bits it can handle dates beyond 2038 without problems.

Here goes:

{
static const unsigned char maxmd[] = { 31, 28, 31,
30, 31, 30, 31, 31, 30, 31, 30, 31 };

// return from + one_month;
// the function also ignore dst issues, the time
// within a day is always returned as midnight.
struct tm k;

k = *localtime(from);
if (++(k.tm_mon) == 12) {
k.tm_mon = 0;
++(k.tm_year);
}
// check if mday is 28 or higher
if (k.tm_mday >= 28) {
k.tm_mday = maxmd[k.tm_mon];
if (k.tm_mon == 1 && ((k.tm_year + 1900)) & 3 == 0)
k.tm_mday = 29;
}
// set time to midnight.
k.tm_hour = k.tm_min = k.tm_sec = 0;

}

The leap year test require some explanation.

In the range we assume (1970 to 2038) there are no exceptions for century years so every 4th year is a leap year. (Year 2000 was a leap year). To test if year % 4 == 0 is the same as test if (year & 3) == 0.

k.tm_year hold the year - 1900 so k.tm_year + 1900 is the year.

You might wonder why I bother with localtime when mktime() doesn't work very well it. Yes, I could have used gmtime but then the date might have gotten wrong. If UTC date is 14th but your local date is 15th you might want so to move it ahead to 15th. Now this would work properly for a date like 15th since the error when converting back to time_t using mktime would cancel this effect. The problem would be with a date like 28th of february in a non leap year which becomes 27th under the same conditions and so translates to 27th the next month and then when doing mktime becomes 28th of march in local time instead of 31st of march as it should.

So, we do localtime() and then after calling mktime we add the timezone adjustment for your zone to get the return value to be midnight your place.

The TZ_ADJUSTMENT is of course a value that varies with where you are.

Alf
0

LVL 1

Author Comment

ID: 8212282

(Points upped to 250 due to my laziness..)

k = *localtime(from);

Gives me the error: error C2664: 'localtime' : cannot convert parameter 1 from 'long' to 'const long *'.

Also, how do I covert a CTime var to a time_t structure and back again.
0

LVL 46

Expert Comment

ID: 8212555

k = localtime (from);

Should get you a lot closer.  :)

The "*" dereferences the returned result which makes it look like a "const long *".

Kdo
0

LVL 46

Expert Comment

ID: 8212557

k = localtime (from);

Should get you a lot closer.  :)

The "*" dereferences the returned result which makes it look like a "const long *".

Kdo
0

LVL 12

Expert Comment

ID: 8216253
Oh, if you have a CTime variable I guess you are using MFC.

I assumed you used the standard C and C++ time type of time_t.

If you have a CTime variable I believe it is more or less immediate as the CTime variable already have methods to get the day of the month, month of the year and the year.

IF it doesn't then you must convert it to some type that does. The idea is simple enough, just get the date broken down into day, month and year then add the month and put them together to a new time variable.

Some special logic for day in month >= 28 since that is assumed to be 'last day of the month'.

Note, if you use non-standard ways of representing time - such as CTime or System::DateTime (.NET) or SYSTEMTIME (Win32) etc it is a good idea to say so when you ask. If you just ask - people will assume you use standard time type which is time_t.

Alf
0

LVL 12

Expert Comment

ID: 8216277
oops, maybe I should read the question better.... You do say that you have a CTime variable.

Oh well, in any case, I am not sure about the details of that class - I don't have the MFC documentation available here on this Linux machine but I assume it has methods to get the day, month and year, you just get those, add the month, check for the day in month being >= 28 and if so set it to the last day of the month.

The last day is given in the table I originally gave, make sure that you index the table with january == 0, february == 1 etc.

For february you have to make a special test for leapyear. If the year can be 1700, 1800, 1900, 2100, 2200 or 2300 or something like that then you also have to take into account that century years are not leapyears unless they are divisible by 400.

Alf
0

LVL 1

Author Comment

ID: 8217030

I just translated your function to use the CTime struct.
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more adâ€¦
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticallâ€¦
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Botâ€¦
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
###### Suggested Courses
Course of the Month8 days, 23 hours left to enroll