?
Solved

Adding a month to a current date

Posted on 2003-03-26
8
Medium Priority
?
490 Views
Last Modified: 2012-08-14

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
Comment
Question by:bfeddish
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
  • 2
8 Comments
 
LVL 12

Expert Comment

by:Salte
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

by:
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:

time_t add_one_month(time_t from)
{
   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;

   return mktime(&k) + TZ_ADJUSTMENT;
}

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

by:bfeddish
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
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 46

Expert Comment

by:Kent Olsen
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

by:Kent Olsen
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

by:Salte
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

by:Salte
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

by:bfeddish
ID: 8217030

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

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
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 viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.
Suggested Courses

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question