
I did not find any functions in Date-Time library to add a number of months to a given day, or to obtain the last/first day of the month. I mean something like date add_month(const date&, int month_count); date first_date_of_month(const date&); date last_date_of_month(const date&); I understand that I can use the month_iterator instead of add_month, and end_of_month_day instead of last_date_of_month, but since the functionality I described is heavily used in some applications (accounting for instance), it would be much simpler just to call add_month, ... functions. Is there any particular reason why they are not provided? Val Samko http://val.digiways.com

On Sat, 10 Apr 2004 03:43:46 +0100, Val Samko wrote
I did not find any functions in Date-Time library to add a number of months to a given day, or to obtain the last/first day of the month. I mean something like date add_month(const date&, int month_count); date first_date_of_month(const date&); date last_date_of_month(const date&);
Ok, sure. There are some examples that show how to do some of this.
I understand that I can use the month_iterator instead of add_month, and end_of_month_day instead of last_date_of_month, but since the functionality I described is heavily used in some applications (accounting for instance), it would be much simpler just to call add_month, ... functions.
Is there any particular reason why they are not provided?
No, not really -- lack of customer request, basically. add_month is a bit complicated in that it is unclear the desired behavior of adding into the 'ragged month end'. Basically the issue is: date d1(2004,Jan,28); date r1 = add_month(d1,1); //2004-Feb-28, fine date d2(2004,Jan,31); date r2 = add_month(d2,1); //presumably we want to back up to Feb 29? date r3 = add_month(d2,13); //presumably we want to back up to Feb 28? So given that this solution works for your domain, the library does have a solution which is unfortunately only documented in the iterator. Here is how I would write the 3 functions you are asking for: namespace boost { namespace gregorian { date first_date_of_month(const date& orig) { return date(orig.year(), orig.month(), 1); } date last_date_of_month(const date& orig) { int day = gregorian_calendar::end_of_month_day(orig.year(),orig.month()); return date(orig.year(), orig.month(), day); } date add_month(const date& d, int months) { typedef boost::date_time::month_functor<date> add_month_functor; add_month_functor mf(months); return (d + mf.get_offset(d)); } }} Of course the other option would be to include these in the date itself so you could write: date d(2004, Jan, 10); date fd = d.first_date_of_month(); date ld = d.last_date_of_month(); Do you prefer the oo style? For add month we could do: date next = ld.add_month(13); although the prefered syntax for add_month would actually be something like: date next = ld + months(13); There are some technical complications with the last syntax, but it should be doable given some time ;-) Thoughts? Jeff

Jeff, Saturday, April 10, 2004, 4:00:13 PM, you wrote: JG> date d2(2004,Jan,31); JG> date r2 = add_month(d2,1); //presumably we want to back up to Feb 29? JG> date r3 = add_month(d2,13); //presumably we want to back up to Feb 28? I think it is natural to back up to the last day of the month, if the day we have (i.e. 31 in this case) is not present in that month. JG> date first_date_of_month(const date& orig) JG> date last_date_of_month(const date& orig) JG> date add_month(const date& d, int months) JG> Of course the other option would be to include these in the date itself so you JG> could write: JG> date d(2004, Jan, 10); JG> date fd = d.first_date_of_month(); JG> date ld = d.last_date_of_month(); I think, the first approach (non member functions) is better, since a) these function do not need to know the implementation details of the date class b) having some other date class I could easily implement equivalent functions, keeping the syntax consistent. JG> For add month we could do: JG> date next = ld.add_month(13); JG> although the prefered syntax for add_month would actually be something like: JG> date next = ld + months(13); JG> There are some technical complications with the last syntax, but it should be JG> doable given some time ;-) Thoughts? what sort of complications? struct months { months(int m) : mo(m){}; int mo; }; date operator + (const date& d, const month& m) { return add_month(d, m.mo); } Anyway, I think, three namespace level functions would be sufficient. Val Samko http://val.digiways.com

On Sun, 11 Apr 2004 05:27:07 +0100, Val Samko wrote
I think it is natural to back up to the last day of the month, if the day we have (i.e. 31 in this case) is not present in that month.
I agree that backing up seems like the most common desire...
I think, the first approach (non member functions) is better, since a) these function do not need to know the implementation details of the date class b) having some other date class I could easily implement equivalent functions, keeping the syntax consistent.
Ok.
JG> date next = ld + months(13);
JG> There are some technical complications with the last syntax, JG> but it should be doable given some time ;-)
Thoughts? what sort of complications? struct months { months(int m) : mo(m){}; int mo; }; date operator + (const date& d, const month& m) { return add_month(d, m.mo); }
Hmm, point taken. That said, if I add this to the library people will (correctly, I think) expect the following: date d1 += months(3); date d2 = d1 - months(2); date d3 -= months(2); date d3 = d3 + months(-2); to work correctly. The code we have sketched so far won't handle this correctly. Going even further, I don't see why the following isn't allowed: ptime t1(d1); //d1 at midnight t1 = t1 + months(2); And I think this same logic applies to 'years' and 'weeks' as well. This would finally unify the arithmetic concepts in the library -- not to mention make an awful lot of date calculation code very clean.
Anyway, I think, three namespace level functions would be sufficient.
As you can see, I have a slightly grander plan, but it should be compatible with your needs. Do you want these functions in CVS now or are you going to patch your release for now? Jeff

Jeff, Sunday, April 11, 2004, 4:01:02 PM, you wrote: JG> Hmm, point taken. That said, if I add this to the library people will JG> (correctly, I think) expect the following: JG> date d1 += months(3); JG> date d2 = d1 - months(2); JG> date d3 -= months(2); JG> date d3 = d3 + months(-2); JG> to work correctly. The code we have sketched so far won't handle this JG> correctly. Going even further, I don't see why the following isn't allowed: JG> ptime t1(d1); //d1 at midnight JG> t1 = t1 + months(2); JG> And I think this same logic applies to 'years' and 'weeks' as well. This JG> would finally unify the arithmetic concepts in the library -- not to mention JG> make an awful lot of date calculation code very clean. The main problem I see with this syntax is that d + months(MONTHS) + DAYS; is not equivalent to d + DAYS + months(MONTHS); and I sometimes this might lead to the error prone code. This is why I prefer to use add_month function.
Anyway, I think, three namespace level functions would be sufficient.
JG> As you can see, I have a slightly grander plan, but it should be compatible JG> with your needs. Do you want these functions in CVS now or are you going to JG> patch your release for now? I'm currently using my home grown date classes. I will switch to the Date-Time, once these changes will be available in the boost release. Val

On Mon, 12 Apr 2004 07:59:36 +0100, Val Samko wrote
The main problem I see with this syntax is that d + months(MONTHS) + DAYS; is not equivalent to d + DAYS + months(MONTHS); and I sometimes this might lead to the error prone code. This is why I prefer to use add_month function.
True. And this fact has been one factor in keeping this function out of the library before. Still, if it is well documented I'm starting to think the risk might be worth it since 'month' becomes a first class object that can be used in interfaces and as a data member in classes.
I'm currently using my home grown date classes. I will switch to the Date-Time, once these changes will be available in the boost release.
You are aware that this won't be for a couple months (at least), right? Jeff

Jeff,
The main problem I see with this syntax is that d + months(MONTHS) + DAYS; is not equivalent to d + DAYS + months(MONTHS); and I sometimes this might lead to the error prone code. This is why I prefer to use add_month function.
JG> True. And this fact has been one factor in keeping this function out of the JG> library before. Still, if it is well documented I'm starting to think the JG> risk might be worth it since 'month' becomes a first class object that can be JG> used in interfaces and as a data member in classes. True. In any case, there is a point of having the add_month(const date&, int) function as well.
I'm currently using my home grown date classes. I will switch to the Date-Time, once these changes will be available in the boost release.
JG> You are aware that this won't be for a couple months (at least), right? Sure. Val

From: "Jeff Garland" <jeff@crystalclearsoftware.com>
No, not really -- lack of customer request, basically. add_month is a bit complicated in that it is unclear the desired behavior of adding into the 'ragged month end'. Basically the issue is:
date d1(2004,Jan,28); date r1 = add_month(d1,1); //2004-Feb-28, fine date d2(2004,Jan,31); date r2 = add_month(d2,1); //presumably we want to back up to Feb 29? date r3 = add_month(d2,13); //presumably we want to back up to Feb 28?
Adding irregular values is complicated. Typically, when adding "a month" to a date, one expects the same day of the month in the subsequent month. However, if the following month does not include the date in question, then my expectation is that adding a month means adding 30 days. No doubt others would have different expectations (as your example illustrates, of course). You need to allow for varying expectations of how to resolve this irregularity. Consequently, add_month() must either be named more specifically ("add_month_fall_back," for example), with other variations distinguished from it, or you need to specify some sort of policy parameter. One approach for the latter idea is to make add_month() a function template that takes a policy class template parameter which is asked to compute the final date should the new month not include the date. You can default that parameter to a policy of your choosing since that leaves room for clients to customize it as they see fit. Another approach is to take a third function argument of enumeration type that tells add_month() which rule to apply. This restricts the options to those defined by the library, but it is relatively straightforward. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob, Monday, April 12, 2004, 3:26:40 PM, you wrote: RS> From: "Jeff Garland" <jeff@crystalclearsoftware.com>
No, not really -- lack of customer request, basically. add_month is a bit complicated in that it is unclear the desired behavior of adding into the 'ragged month end'. Basically the issue is:
date d1(2004,Jan,28); date r1 = add_month(d1,1); //2004-Feb-28, fine date d2(2004,Jan,31); date r2 = add_month(d2,1); //presumably we want to back up to Feb 29? date r3 = add_month(d2,13); //presumably we want to back up to Feb 28?
RS> Adding irregular values is complicated. Typically, when adding RS> "a month" to a date, one expects the same day of the month in the RS> subsequent month. However, if the following month does not RS> include the date in question, then my expectation is that adding RS> a month means adding 30 days. Why 30 days? And if all you need it to add 30 days, just add 30 days. You do not need the add_month then. I just do not understand your expectations from the add_month function. Can you explain? RS> Consequently, add_month() must either be named more specifically RS> ("add_month_fall_back," for example), with other variations RS> distinguished from it, or you need to specify some sort of policy RS> parameter. Since falling back is somewhat common expectation, having documented it properly, it would be natural to have the add_month function. Other variations (since less common) may have other names. Anyway, what other variations do you propose, which can not be achieved by just adding N days? Val Samko http://val.digiways.com

From: Val Samko <boost@digiways.com>
Monday, April 12, 2004, 3:26:40 PM, you wrote: RS> From: "Jeff Garland" <jeff@crystalclearsoftware.com>
No, not really -- lack of customer request, basically. add_month is a bit complicated in that it is unclear the desired behavior of adding into the 'ragged month end'. Basically the issue is:
date d1(2004,Jan,28); date r1 = add_month(d1,1); //2004-Feb-28, fine date d2(2004,Jan,31); date r2 = add_month(d2,1); //presumably we want to back up to Feb 29? date r3 = add_month(d2,13); //presumably we want to back up to Feb 28?
RS> Adding irregular values is complicated. Typically, when adding RS> "a month" to a date, one expects the same day of the month in the RS> subsequent month. However, if the following month does not RS> include the date in question, then my expectation is that adding RS> a month means adding 30 days.
Why 30 days? And if all you need it to add 30 days, just add 30 days. You do not need the add_month then. I just do not understand your expectations from the add_month function. Can you explain?
I didn't say just add 30 days. I said I'd expect it to be the same day of the month in the following month and if there is no such day in that month, then I'd expect it to be 30 days ahead. Consider: add_month(date(2004, Jan, 30), 1) Since February doesn't have a 30th day, then I'm saying I'd expect "one month" more than January 30th to be February 29th, 30 days after January 30th. Similarly: add_month(date(2004, Jan, 31), 1) I would expect to result in March 1st. Now, I can understand the idea of recognizing that a date is the last day of a given month so that adding "one month" means to advance to the last day of the next month. However, when I think of advancing by a month, I think of adding 1/12 of a year. 365/12 is 30.42, or about 30. Thus, my fallback is to add 30 days. Now, one might argue that adding a month should just be adding 30 days then, but that is already possible. I see add_month() as the means to get closer to the human notion of getting the same day of the next month, with a clear, mathematical fallback.
RS> Consequently, add_month() must either be named more specifically RS> ("add_month_fall_back," for example), with other variations RS> distinguished from it, or you need to specify some sort of policy RS> parameter.
Since falling back is somewhat common expectation, having documented
I don't know how common it is, but I certainly have never used it and wouldn't expect it.
it properly, it would be natural to have the add_month function. Other
Documented properly, the function can do whatever its author deems reasonable. That doesn't preclude mismatched impedence with users, however.
variations (since less common) may have other names. ^^^^^^^^^^^^^^^^^ So you say.
Anyway, what other variations do you propose, which can not be achieved by just adding N days?
I don't know what other variations may arise. We've already seen two, so distinct but clear names already seem warranted. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Tuesday, April 13, 2004, 4:46:11 PM, you wrote: RS> I didn't say just add 30 days. I said I'd expect it to be the RS> same day of the month in the following month and if there is no RS> such day in that month, then I'd expect it to be 30 days ahead. Do you actually need such a functionality in any applications? RS> Now, one might argue that adding a month should just be adding 30 RS> days then, but that is already possible. I see add_month() as RS> the means to get closer to the human notion of getting the same RS> day of the next month, with a clear, mathematical fallback. falling back to the last day of the month is a perfect "mathematical" fallback as well. It's just a matter of documentation.
Anyway, what other variations do you propose, which can not be achieved by just adding N days?
RS> I don't know what other variations may arise. We've already seen RS> two, so distinct but clear names already seem warranted. I understand this if you actually need the functionality you described in any applications. Otherwise, I'd hate to type add_month_or_fallback_to_last_day each time I need this simple operation. Val Samko http://val.digiways.com

From: Val Samko <boost@digiways.com>
Tuesday, April 13, 2004, 4:46:11 PM, you wrote:
RS> I didn't say just add 30 days. I said I'd expect it to be the RS> same day of the month in the following month and if there is no RS> such day in that month, then I'd expect it to be 30 days ahead.
Do you actually need such a functionality in any applications?
No. The point I was making is that were I to call such a function, that's the behavior I'd expect. Does not having a current need for it make it less valid?
RS> Now, one might argue that adding a month should just be adding 30 RS> days then, but that is already possible. I see add_month() as RS> the means to get closer to the human notion of getting the same RS> day of the next month, with a clear, mathematical fallback. falling back to the last day of the month is a perfect "mathematical" fallback as well. It's just a matter of documentation.
It isn't mathematical, by which I meant predictable, without accounting for whether the day of the current month is available in the subsequent month. That is, yours may fall back anywhere from zero to three days. Mine is certain to advance to the same day of the month or exactly 30 days beyond the start; that's far more predictable.
Anyway, what other variations do you propose, which can not be achieved by just adding N days?
RS> I don't know what other variations may arise. We've already seen RS> two, so distinct but clear names already seem warranted.
I understand this if you actually need the functionality you described in any applications. Otherwise, I'd hate to type add_month_or_fallback_to_last_day each time I need this simple operation.
I don't think it must be that dramatic. If the function is to have a unique name, rather than using one of the other techniques I mentioned, I should think that "add_month_with_fallback" would be sufficient to clarify its behavior. It boils down to this: does everyone but me think the fallback behavior is "correct?" If so, ignore me. I can always implement my own "add_month." If not, then yours should not be *the* definition of "add_month" should it? In that case, shouldn't you mitigate the potential for confusion and allow for different schemes? -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart wrote:
From: Val Samko <boost@digiways.com>
Tuesday, April 13, 2004, 4:46:11 PM, you wrote:
RS> Now, one might argue that adding a month should just be adding 30 RS> days then, but that is already possible. I see add_month() as RS> the means to get closer to the human notion of getting the same RS> day of the next month, with a clear, mathematical fallback. falling back to the last day of the month is a perfect "mathematical" fallback as well. It's just a matter of documentation.
It isn't mathematical, by which I meant predictable, without accounting for whether the day of the current month is available in the subsequent month. That is, yours may fall back anywhere from zero to three days. Mine is certain to advance to the same day of the month or exactly 30 days beyond the start; that's far more predictable.
I'm not so sure. If I get paid once a month, at the end of the month, I expect a paycheck on January 31, February 28/29, March 31, etc. I would be highly surprised (and annoyed) if my February paycheck arrived on March 2. If the payroll program was using your algorithm I would not get paid again until April 2. Using your algorithm, I can add one to a month and end up two months ahead. I note that your interpretation only differs from Val's when adding one month to January; in all other months your interpretation behaves the same as his. So the argument is about only two or three days a year... The interpretation that makes sense to me is: adding one month means the same day of the next month, unless the date's not valid, in which case I expect moving backwards to the latest date of said month. That's what humans do when you say "next month", so I would think anything else would be surprising. Bob Bell

From: Robert Bell <belvis@imageworks.com>
Rob Stewart wrote:
From: Val Samko <boost@digiways.com>
Tuesday, April 13, 2004, 4:46:11 PM, you wrote:
RS> Now, one might argue that adding a month should just be adding 30 RS> days then, but that is already possible. I see add_month() as RS> the means to get closer to the human notion of getting the same RS> day of the next month, with a clear, mathematical fallback. falling back to the last day of the month is a perfect "mathematical" fallback as well. It's just a matter of documentation.
It isn't mathematical, by which I meant predictable, without accounting for whether the day of the current month is available in the subsequent month. That is, yours may fall back anywhere from zero to three days. Mine is certain to advance to the same day of the month or exactly 30 days beyond the start; that's far more predictable.
I'm not so sure. If I get paid once a month, at the end of the month, I expect a paycheck on January 31, February 28/29, March 31, etc. I would be highly surprised (and annoyed) if my February paycheck arrived on March 2. If the payroll program was using your algorithm I would not get paid again until April 2.
If you want that behavior, you wouldn't use add_month() as Val defined it anyway, because you'd need it to snap to the last business day of the month. Nevertheless, let's assume an application in which you want the snapping to the last day of the month. Val's suggested semantics gives it to you. I have no argument with that. What I'm arguing is that I think "one month from now" means around 30 days hence. Consider making an appointment with someone for "a month from now." Usually that means increment the month and leave the day of the month alone. But when there are fewer days in the following month than in the current month and you're very near the end of the current month, I wouldn't think twice about skipping ahead by 30 days or maybe four weeks (to give yet another interpretation). It's like the difference between reals and fractions with arbitrarily constrained denominators (like on an ordinary ruler). You give up accuracy to stay within the allowable units (say, 1/16ths of an inch or millimeters). I see "add a month" as an approximation that tries to snap to something around 30 days in the future. If the current month has 31 days, then the result would be 31 days hence. If the current month has 28 days, then the result would be 30 days hence.
Using your algorithm, I can add one to a month and end up two months ahead.
No, the month number or the day of the month would advance by two, but you'd only be 30 or 31 days ahead.
I note that your interpretation only differs from Val's when adding one month to January; in all other months your interpretation behaves the same as his. So the argument is about only two or three days a year...
That's an interesting point. Without thinking about it, I expected it to apply when adding a month to March 31, May 31, etc., but we do arrive at the same answer in each case.
The interpretation that makes sense to me is: adding one month means the same day of the next month, unless the date's not valid, in which case I expect moving backwards to the latest date of said month. That's what humans do when you say "next month", so I would think anything else would be surprising.
Let's look at the example given in other posts: add_month(add_month(d, 1), 1) If such code -- however those two calls actually come about -- occurs when d is late in January, it only advances by 56 days, well less than 1/6 of a year, with your interpretation. With mine, it would advance by 61 days, which is very nearly 1/6 of a year. Thus, mine gives more predictable results when considering a "month" to be approximately 1/12 of a year, which I do. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Tuesday, April 13, 2004, 11:25:52 PM, you wrote:
Do you actually need such a functionality in any applications?
RS> No. The point I was making is that were I to call such a RS> function, that's the behavior I'd expect. Does not having a RS> current need for it make it less valid? I think it does. One could think of 10 other behaviours of add_month, starting from the random day of the next month, but they would be nothing but useless. And I can not imagine any real use for the add_month behaviour you have described. RS> It isn't mathematical, by which I meant predictable, without RS> accounting for whether the day of the current month is available RS> in the subsequent month. That is, yours may fall back anywhere RS> from zero to three days. Mine is certain to advance to the same RS> day of the month or exactly 30 days beyond the start; that's far RS> more predictable. Predictable? It is definitely not predictable. I think, most people expect that after d2 = add_month(add_month(d1, 1), -1) d1 and d2 are in the same month. And your definition breaks this obvious rule. Val Samko http://val.digiways.com

From: Val Samko <boost@digiways.com>
Tuesday, April 13, 2004, 11:25:52 PM, you wrote:
Do you actually need such a functionality in any applications?
RS> No. The point I was making is that were I to call such a RS> function, that's the behavior I'd expect. Does not having a RS> current need for it make it less valid?
I think it does. One could think of 10 other behaviours of add_month, starting from the random day of the next month, but they would be nothing but useless. And I can not imagine any real use for the add_month behaviour you have described.
Clearly you think my notion of adding a month is akin to randomly selecting a day in the next month. Thanks. I hadn't realized my mind was so odd. Seriously, when I schedule something for a month hence, I'm not concerned about whether that entirely skips the month of February unless it is an event that is supposed to be the 3rd Tuesday of the month, or something. Instead, I want it to be about 1/12 of a year in the future. Consider using a natural language task scheduler that permits scheduling things with phrases like "tomorrow," "next week," and next month." I'd expect "next month" to mean increment the month and clip to the number of days in that month. However, if I could type "a month from now," I'd expect it to add 1/12 of a year; that is, I'd expect 30 or 31 days from now.
RS> It isn't mathematical, by which I meant predictable, without RS> accounting for whether the day of the current month is available RS> in the subsequent month. That is, yours may fall back anywhere RS> from zero to three days. Mine is certain to advance to the same RS> day of the month or exactly 30 days beyond the start; that's far RS> more predictable. Predictable? It is definitely not predictable. I think, most people expect that after d2 = add_month(add_month(d1, 1), -1) d1 and d2 are in the same month. And your definition breaks this obvious rule.
When did we start discussing negative increments? Wouldn't that be called subtract_month()? Really, though, let's follow your logic using January 30th. add_month(d1, 1) gives you February 28th (maybe 29th). Then, add_month(d2, -1) gives you January 28th. How is that logical? Now let's examine my logic in that context: January 30th to March 1 to February 1. Which gives a better answer? Neither. Yours offers the benefit of returning to the same month, but neither returns to the same date which means it is simply not a reversible operation. Consequently, your argument is specious. Given my natural language scheduler example, I'm led to suggest what you want is "next_month" and what I want is "add_month." That is, the names are distinct for the distinct behaviors and "next_month" clearly -- to me -- connotes what you're asking for. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;
participants (4)
-
Jeff Garland
-
Rob Stewart
-
Robert Bell
-
Val Samko