From: Jeff Garland (jeff_at_[hidden])
Date: 2004-04-24 21:50:19
On Sat, 24 Apr 2004 20:24:19 -0400, Howard Hinnant wrote
> On Apr 24, 2004, at 9:35 AM, Jeff Garland wrote:
> 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! :-) ).
And I thought I was the only crazy person ;-)
> 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
> date = feb/last/2004; // same as feb/29/2004
> date += year(1); // ok, feb/28/2005
It's an interesting approach. Basically it is a 'construction' policy that
controls month addition rules -- storing the policy to use in the date itself.
Of course the alternative is to store that policy decision outside the date.
It doesn't matter for a few dates, but if I happen to have 10,000 dates in a
collection for some planning application I might want to avoid the extra
overhead. Especially given that it is unlikely that the policy would be
different for each date.
> ... snip loop results...
> 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
Yet another variation on the month addition rules. And I can imagine is a
fairly common case. Example: Last Friday of the month is payday.
> I'm currently using 64 bits to implement this (sizeof(date) == 8 on
> a 32 bit machine).
boost::gregorian::date uses 32 bits internally.
> 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. :-)
Hmm, I'm guessing I might be in the satisfy the world category ;-) So
seriously, I'm primarily interested in the requirements that drive the
features and the features themselves. It would take alot for boost.date_time
to move toward the implementation approach you are using. And even if there
was agreement it was the right thing, I think the current approach can achieve
the same aims without increasing the size of the date representation. With a
slightly different interface, of course.
In particular, I'm interested in the 'date generation' requirements.
One result of last weeks discussion is that I've been re-evaluating what
boost.date_time offers, and I see some holes. I've been thinking about some
new date generator functions and some of them overlap with what you outlined.
Here's some new date generation functions I've been thinking about adding:
date next_weekday(const date& d, weekday wd, weeks w=weeks(1));
//advance to the next monday -- if monday then 7 days
//if weeks > 1 then first advance the number of weeks and then
//to the weekday
date previous_weekday(const date& d, weekday wd, weeks w=weeks(1));
//advance to previous weekday
date date_from_weekday_number(greg_year y, week_number wn, weekday wd);
// 2004, 2, Monday == Jan 05 2004
// 2004, 1, Monday == Dec 29 2003 -- yes that's right, iso week numbers
// are very weird -- the year rolls back
// 2003, 52, Sat == Dec 27 2003
These functions don't generate a date, but rather generate the distance
between a date using a rule:
days days_until_weekday(const date& d, weekday wd, weeks w=weeks(1));
//if d is on Sunday and wd == Monday return 1
//if d is on Sunday and wd == Sunday return 0
//if weeks > 1 then first advance the number of weeks and then to
days days_before_weekday(const date& d, weekday wd, weeks w=weeks(1));
//if d is on Sunday and wd == Friday return 2
//if d is on Sunday and wd == Sunday return 0
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk