# Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2004-04-24 19:24:19

On Apr 24, 2004, at 9:35 AM, Jeff Garland wrote:

> On Fri, 23 Apr 2004 23:22:34 -0400, Daryle Walker wrote
>> [NOTE: I haven't worked on this library; I'm just going by the posts
>> I see here.]
>>
>> For this increment/decrement by a month problem, is there any way to
>> store a date with only a month resolution? Nothing smaller will be
>> stored, so day crossovers won't be a problem.
>
> I think what you mean is a 'duration' with month resolution. Ala
> months m1(3);
> months m2(2);
> months m3 = m2 + m1;
> //...
>
> This can be done, but the issue is that to work with the date timepoint
> calculation is done at single day resolution. And there isn't a fixed
> number
> of days in a month, so you CANNOT say:
> days dd(28) == months(1); //proposition 1
>
> Similarly the following is NOT true:
> days dd(365) == years(1); //proposition 2
>
> Conversly, you can always say this:
> days dd(28) == weeks(4);
>
> So the problem is while a week is a fixed length that is well known to
> be 7
> days, a month and year are not. The length of a month and year
> depends on the
> context of the date. So people want the following sort of behavior:
> date d1 += months(12); //if d1 is a leap year add 366 days instead
> of 365

I've also only been skimming the date-time += month issue. I have an
hobbyist's interest in the subject having lovingly crafted and
maintained a date class of my own over the last decade (hasn't
everybody! :-) ).

Fwiw, here's what I'm currently doing, and it was inspired by reading
the discussion in boost. When I back-fitted my revised date class into
my existing applications (holiday/birthday reminder, mortgage
computations, and the ever important stock option calculator!) the
transition was very smooth. Of course what I'm using dates for is just
tinker-toy stuff compared to a commercial quality date-aware app so
please take this for what it's worth...

gregorian::date can not hold an invalid date. If an attempt is made to
create or assign to a gregorian::date with a value that would result in
an invalid date, a gregorian::bad_date exception is thrown.

Months can be added to dates, but may result in an invalid date
(throwing an exception):

date = mar/31/2004;
date += month(1); // error! bad_date thrown, date uneffected

However mar/31/2004 can also be specified with "last":

date = mar/last/2004;
date += month(1); // ok, apr/30/2004

mar/31/2004 == mar/last/2004 but the latter is tagged with extra
information that implies the semantics of "last day of the month"
rather than "31st day of the month". Similarly for adding years:

date = feb/29/2004;
date += year(1); // error, bad_date thrown

but:

date = feb/last/2004; // same as feb/29/2004
date += year(1); // ok, feb/28/2005

The following loop prints out the last day of each month:

for (date d = jan/last/2004, end = dec/last/2004; d <= end; d +=
month(1))
std::cout << d << '\n';

01/31/04
02/29/04
03/31/04
04/30/04
05/31/04
06/30/04
07/31/04
08/31/04
09/30/04
10/31/04
11/30/04
12/31/04

There's similar functionality for finding the nth day-of-week of a
month/year, or the last day-of-week of a month/year.

for (date d = last*sat/jan/2004, end = last*sat/dec/2004; d <= end; d
+= month(1))
std::cout << d << '\n';

01/31/04
02/28/04
03/27/04
04/24/04
05/29/04
06/26/04
07/31/04
08/28/04
09/25/04
10/30/04
11/27/04
12/25/04

I'm currently using 64 bits to implement this (sizeof(date) == 8 on a
32 bit machine). I'd be happy to share more details if there is
interest. This is just a hobby for me. I'm not trying to write the
"date class that satisfies the world". I'm satisfied and in hobbies
that's all that counts. :-)

-Howard