
Ummm, OK, you made it work, but why? Why would you want to be able to call add_month() on a date and have it always represent the day before the last day of the month?
date d = August 30; // add six months. add_month(d); // September 30; add_month(d); // October 31? add_month(d); // November 30 add_month(d); // December 31? add_month(d); // January 30 add_month(d); // February 28/29 add_month(d); // March 28? 29? 30? 31? Just looking this there is no way to predict which day of the month the last call is going to be. I'd find it surprising that (d + year) != (12 * months) + d; I think you are looking for a simplistic function for a complex problem. IMO its a trap for the unwary and should be called out as such. I can see the need for LAST, but my contention is that its not enough information to do the least surprising thing. The easiest way to resolve this is to either write a FAQ, and or have a dumb rounding month adding function that can screw up the dates for those times when "meet you next month" is the right answer. Yours, -Gary-

Hi, I have worked for a french accountancy and sales management software company for many years and we have big needs in date calculation and would ba happy to find a standard class covering our needs. We ended up having multiple date classes because people were unable to agree on topics such as this one. I even tried do create a 'final' date class which tried to merge the others (half a success because of too much interface disparity). The debates we had here and this thread prove that you cannot have a parameterless add_month(...);this is no trivial operation; by the way, this means no add_year(...) also (due to the 29th feb). IMHO, add_month should follow this rules : - be reversible; either by having a negative number of month as a paremeter, or by using sub_month, so that sub_month( add_month(d) ) == d; for every valid date d. - if used twelve times it should be able to give you the same date one year from now (except for the 29th feb of course). - if it can be parametrized using a number of month, adding n months should be equivalent to adding n times a month (and any other combinations for a total of n months). - the user should be able to specify the expected behaviour: - saturation ( never go past the end of next month): most expected behaviour I guess - end/begin ( from last-n to last-n next month with n<4-5): this THE standard behaviour for payments date. - overflow ( going from 31 january to 1-3thd march): not reaaly needeed because you can achieve the same results adding 30/31 days to current date. - eventually others to be define. what we cannot have : - a simple add_month(...) prototype hiding the complexity involved. - use fake dates for thing such as LAST because this state would probably be lost during seralization. - throw an exception for complex case: IMHO offering exceptions as an extension mechanism is bad design. - use 'virtual' days (30th Februray) because this state would probably be lost during seralization and would never be accepted by a DB engine. For us, date is a basic type needeed everywhere and we NEED month calculation, that's why we keep designing date classes. We have funkier date calculation algorithms which would not fit in a standard class, but I will gladly explain them if someone wants to. Cyrille Dupuydauby

On Thu, 15 Apr 2004 09:00:32 +0200, Cyrille Dupuydauby wrote
Hi, I have worked for a french accountancy and sales management software company for many years and we have big needs in date calculation and would ba happy to find a standard class covering our needs.
We ended up having multiple date classes because people were unable to agree on topics such as this one. I even tried do create a 'final' date class which tried to merge the others (half a success because of too much interface disparity).
Thx for the post Cyrille. I always like to hear about these sorts of experiences. I've seen exactly this sort of problem arise as well which was one of my motivators for writing the library.
The debates we had here and this thread prove that you cannot have a parameterless add_month(...);this is no trivial operation; by the way, this means no add_year(...) also (due to the 29th feb).
Yes, add_year and add_month have the same problem. I consider these logical operations. add_days and add_weeks are, however, perfectly defined and obey normal mathemtical rules.
IMHO, add_month should follow this rules : ...snip rules...
I'm going to address your rules and issues in an upcoming summary post...
For us, date is a basic type needeed everywhere and we NEED month calculation, that's why we keep designing date classes. We have funkier date calculation algorithms which would not fit in a standard class, but I will gladly explain them if someone wants to.
I would very much like to hear about these requirements. Not that I believe that the library should support all of them directly -- only that the library facilities should make it to implement these. Jeff

From: "Powell, Gary" <powellg@amazon.com>
From: Rob Stewart
Ummm, OK, you made it work, but why? Why would you want to be able to call add_month() on a date and have it always represent the day before the last day of the month?
date d = August 30;
// add six months. add_month(d); // September 30; add_month(d); // October 31?
October 30
add_month(d); // November 30 add_month(d); // December 31?
December 30
add_month(d); // January 30 add_month(d); // February 28/29
According to my scheme: March 1/2
add_month(d); // March 28? 29? 30? 31?
According to my scheme: April 1/2
Just looking this there is no way to predict which day of the month the last call is going to be. I'd find
So? You'd have to know whether you were passing over February in a leap year anyway, which adds variability. Neither scheme is far from August 30 + 7 * 30 days. (According to my quick check, August 30 + 7 * 30 days would be March 29/30.) Now, with add_month(d, 7), where d is August 30, the result would easily be March 30 (add 7 to the month, advancing the year if needed; if the starting day of the month (30) is not in the target month, fall back to adding 7 * 30 days). Since you're adding an irregular value, these differences shouldn't be surprising in the least. Now, if there was a next_month() function, I'd expect this progression: date d = August 30; next_month(d); // September 30 next_month(d); // October 30 next_month(d); // November 30 next_month(d); // December 30 next_month(d); // January 30 next_month(d); // February 28/29 next_month(d); // March 28/29 and: date d = August 30; next_month(d, 7); // March 30 Curiously, though, no one has mentioned "next month" as in the same day of the same week of next month, or the same ordinal day of the week of next month. You could say that these are much more specialized, and don't need to be handled by the library, but think about regular first Monday of the month meetings or other similar scheduling needs. Don't those deserve some attention? Isn't what you've been asking of add_month() really just a case of this broader functionality? That is, you want next_month(d, n, same_day_of_month_or_fall_back), but others may want next_month(d, n, same_ordinal_day_of_week), etc.
it surprising that
(d + year) != (12 * months) + d;
Actually, that expression should easily be an equality. Adding 12 * months to a date should mean to increment the month by 12 and the year by one and that should do the same thing as adding a year to the date.
I think you are looking for a simplistic function for a complex problem. IMO its a trap for the unwary and should be called out as such.
Why is my notion of add_month() "simplistic" and why isn't yours?
I can see the need for LAST, but my contention is that its not enough information to do the least surprising thing.
I don't understand why not. I can understand wanting to get the last day of each month as you increment from month to month, but I can't understand needing the second to last day or third to last day, etc., for any but the oddest situations. LAST seems like a valuable concept if we don't get the more general next_month(d, n, last_day_of_month), next_month(d, n, second_to_last_day_of_month), etc.
The easiest way to resolve this is to either write a FAQ, and or have a dumb rounding month adding function that can screw up the dates for those times when "meet you next month" is the right answer.
I can see how you'd think that, given that you want your preferred behavior to be the "dumb rounding" scheme in the library. At the very least, I think there should be a distinction between add_month() and next_month(). Whether the library ever provides for more complicated schemes is another matter. (A more general mechanism that applies a rule for finding the right day of the new month could be abstracted behind the names "add_month" and "next_month.") -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On Thu, 15 Apr 2004 09:56:55 -0400 (EDT), Rob Stewart wrote
Curiously, though, no one has mentioned "next month" as in the same day of the same week of next month, or the same ordinal day of the week of next month. You could say that these are much more specialized, and don't need to be handled by the library, but think about regular first Monday of the month meetings or other similar scheduling needs. Don't those deserve some attention? Isn't what you've been asking of add_month() really just a case of this broader functionality? That is, you want next_month(d, n, same_day_of_month_or_fall_back), but others may want next_month(d, n, same_ordinal_day_of_week), etc.
Yes, I think this deserves attention and it is already supported in the library. There are a set of 'date generator' classes in the library that support the generation of a date from logical information like: last Monday in January: last_kday_of_month lkm(Monday, Jan); //supply the missing data to generate a concreate date -- year in this case date last_mon_jan_2004 = lkm.getDate(2004); //26th date last_mon_jan_2003 = lkm.getDate(2003); //27th I'm starting to think this is where the next_month functionality should belong. Because it allows for the library to easily support a variety of different algorithms. And user extensions can follow the same model so as to make custom behaviors integrate seemlessly. So, I'm thinking something like: increment_month_with_end_of_month_rollback add_quarter_year(3); date d(...); //whatever d = add_quarter_year(d); BTW, I'm still not opposed to other syntaxes and first class representations of months to allow simplified syntax. However, I think that this would need to build on top of a pure functional foundation. Jeff

From: "Jeff Garland" <jeff@crystalclearsoftware.com>
On Thu, 15 Apr 2004 09:56:55 -0400 (EDT), Rob Stewart wrote
Curiously, though, no one has mentioned "next month" as in the same day of the same week of next month, or the same ordinal day of the week of next month. You could say that these are much more specialized, and don't need to be handled by the library, but think about regular first Monday of the month meetings or other similar scheduling needs. Don't those deserve some attention? Isn't what you've been asking of add_month() really just a case of this broader functionality? That is, you want next_month(d, n, same_day_of_month_or_fall_back), but others may want next_month(d, n, same_ordinal_day_of_week), etc.
Yes, I think this deserves attention and it is already supported in the library. There are a set of 'date generator' classes in the library that support the generation of a date from logical information like: last Monday in January:
last_kday_of_month lkm(Monday, Jan); //supply the missing data to generate a concreate date -- year in this case date last_mon_jan_2004 = lkm.getDate(2004); //26th date last_mon_jan_2003 = lkm.getDate(2003); //27th
Yes, I see them.
I'm starting to think this is where the next_month functionality should belong. Because it allows for the library to easily support a variety of different algorithms. And user extensions can follow the same model so as to make custom behaviors integrate seemlessly.
That does make sense, but so does the "date wrapper" idea. The latter provides a convenient means to use operator overloading meaningfully while making the behavior of those operators specific to the wrapper type. I think the date wrapper approach will prove easier to use, but more cumbersome to implement.
So, I'm thinking something like: increment_month_with_end_of_month_rollback add_quarter_year(3); date d(...); //whatever d = add_quarter_year(d);
BTW, I'm still not opposed to other syntaxes and first class representations of months to allow simplified syntax. However, I think that this would need to build on top of a pure functional foundation.
With the "date wrapper" idea, I'm not sure this holds. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On Mon, 19 Apr 2004 14:22:53 -0400 (EDT), Rob Stewart wrote
That does make sense, but so does the "date wrapper" idea. The latter provides a convenient means to use operator overloading meaningfully while making the behavior of those operators specific to the wrapper type. I think the date wrapper approach will prove easier to use, but more cumbersome to implement.
I have no idea what the 'date wrapper approach' is... Jeff

From: "Jeff Garland" <jeff@crystalclearsoftware.com>
On Mon, 19 Apr 2004 14:22:53 -0400 (EDT), Rob Stewart wrote
That does make sense, but so does the "date wrapper" idea. The latter provides a convenient means to use operator overloading meaningfully while making the behavior of those operators specific to the wrapper type. I think the date wrapper approach will prove easier to use, but more cumbersome to implement.
I have no idea what the 'date wrapper approach' is...
It took a little bit, but I tracked down the message. I had deleted it by the time you asked. http://aspn.activestate.com/ASPN/Mail/Message/boost/2053807 -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On Tue, 20 Apr 2004 15:37:07 -0400 (EDT), Rob Stewart wrote
From: "Jeff Garland" <jeff@crystalclearsoftware.com>
I have no idea what the 'date wrapper approach' is...
It took a little bit, but I tracked down the message. I had deleted it by the time you asked.
Yeah, I read that but there was insufficient detail for me to understand. How would allow_clipping_to_eom(d) + 2*months; actually work? I'm assuming it would be something like: date_wrapper allow_clipping_to_eom(const date& d) with some set of operators defined on date_wrapper to work with 2*months? Jeff

From: "Jeff Garland" <jeff@crystalclearsoftware.com>
On Tue, 20 Apr 2004 15:37:07 -0400 (EDT), Rob Stewart wrote
From: "Jeff Garland" <jeff@crystalclearsoftware.com>
I have no idea what the 'date wrapper approach' is...
It took a little bit, but I tracked down the message. I had deleted it by the time you asked.
Yeah, I read that but there was insufficient detail for me to understand. How would
allow_clipping_to_eom(d) + 2*months;
actually work? I'm assuming it would be something like:
date_wrapper allow_clipping_to_eom(const date& d)
with some set of operators defined on date_wrapper to work with 2*months?
I assumed that the wrapper type name was "allow_clipping_to_eom" and that it had a ctor taking a date. Thus, the expression above would create an unnamed temporary of type allow_clipping_to_eom and then some namespace scope operator +() would take an allow_clipping_to_eom and a typeof(2*months), returning a date. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;
participants (4)
-
Cyrille Dupuydauby
-
Jeff Garland
-
Powell, Gary
-
Rob Stewart