Boost logo

Boost Users :

From: Jeff Garland (jeff_at_[hidden])
Date: 2002-12-26 19:00:24


> I am an a process of adapting our codebase to boost date_time library, and one quite
> annoying problem I encountered is that date iterators conform to InputIterator model,
> rather then Random Access Iterator.

The reason for this is that it is unclear in all cases that an operation is
easily reversed. In particular, the problem comes about with handling the
end of the month. Say for example you start an iterator on Jan 30. When you
iterate to February what happens? Well the rule the supplied iterator is to
back up to the end of the February -- either the 27 or 28th for a leap year.
Given that these rules are complex and at least possibly non-reversible I
tried to limit the exposure of the iterator: hence input iterator. In
retrospect, however, it could probably be RandomAccess because I can't
give you an actual case where making the iterator reverse is an actual
issue.
 
> By the nature of application I have to calculate quite often something like
> current date plus N months.
>
> The only way I see so far is doing something like
>
> date d(2002,Dec,26);
> month_iterator mi(d);
> for( size_t i=0; i < 5; ++i)
> ++mi;
> d = *mi;
>
> This is rather awkward, not to mention inefficient.

If you want to use the iterator you can simply do the following:

month_iterator mi(d, 3); // configure iterator to add 3 months at a time.
mi++; //adds 3 months.

If you don't want to use the iterator there are a couple of
possible solutions. One is to do the following:
  int N = 3; //add 3 months
  date d(...);// constructed however
  date d1(d.year(), d.month()+N, d.day());
Well, except that this doesn't handle year wrap arounds and
other the issues associated with the end of the month as described
above. So you have to write some supporting code to handle
these issues. It's not that hard -- you might take a look at
the boost/date_time/adjust_functors.hpp for ideas.

If you are happy with the rules associated with the iterator for
the end of month handling then you can just use the functor that
is used by the iterator directly. There is an example in
libs/date_time/examples/gregorian/add_month.cpp. It looks like:

  using namespace boost::gregorian;
  typedef boost::date_time::month_functor<date> add_month;

  date d = day_clock::local_day();
  add_month mf(3); //add by 3 months at a time
  date d2 = d + mf.get_offset(d);

But don't try
  date d2 = d - mf.get_offset(d);

because you will get the wrong answer. Basically what you need
is a month functor that calculates the reverse offset for going
backward. The code that's there in the functor could probably
be made bi-directional, but it would take some thought and work.

> BTW, how am I supposed to roll few months back? It is a forward
> iterator not even a bidirectional.

See above. I'm adding the month subtraction function to my todo
list -- unless you want to take a crack at it ;-)
 
> Even more critique: the iterator is not exactly InputIterator, since it
> has only prefix increment, and no postfix one.

Right -- will correct, thanks.

Jeff


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net