I've updated the DateTime.pm code to do date math as has been discussed
(on local, not UTC datetime, so that 1 day is not always 24 hours).

I've also updated the docs a bit.  I'd appreciate any comments people
might have on them before the next release, because it's a confusing topic
and I'm trying to be as clear as possible.


---------------------------------------------------------------------------

=head2 How Date Math is Done

It's important to have some understanding of how date math is
implemented in order to effectively use this module and
C<DateTime::Duration>.

The parts of a duration can be broken into three parts.  These are
months, days, and seconds.  Adding one month to a date is different
than adding 4 weeks or 28, 30, or 31 days.  Similarly, due to DST and
leap seconds, adding a day can be different than adding 86,400
seconds.

C<DateTime.pm> always adds (or subtracts) days and seconds first.
Then it normalizes the seconds to handle second values less than 0 or
greater than 86,400 (or 86,401).  Then it adds months.

This means that adding one month and one day to February 28, 2003 will
produce the date April 1, 2003, not March 29, 2003.

=head3 Local/UTC and 24 hours/1 day

When doing date math, you are changing the I<local> datetime.  This is
generally the same as changing the UTC datetime, except when a change
crosses a daylight saving boundary.  The net effect of this is that 24
hours is not always the same as 1 day.

Specifically, if you do this:

  my $dt = DateTime->new( year => 2003, month => 4, day => 5,
                          hour => 2,
                          time_zone => 'America/Chicago',
                        );
  $dt->add( days => 1 );

then you will produce an I<invalid> local time, and therefore an
exception will be thrown.

However, this works:

  my $dt = DateTime->new( year => 2003, month => 4, day => 5,
                          hour => 2,
                          time_zone => 'America/Chicago',
                        );
  $dt->add( hours => 24 );

and produces a datetime with the local time of "03:00".

Another way of thinking of this is that when doing date math, each of
the seconds, days, and months components is added separately to the
local time.

So when we add 1 day to "2003-02-22 12:00:00" we are incrementing
adding one to the day component, to produce 23.  If we add 24 hours,
however, we're adding "24 * 60 * 60" sceonds to the time component,
and then normalizing the result (because there is no "36:00:00").

If all this makes your head hurt, there is a simple workaround.  Just
convert your datetime object to the "UTC" time zone before doing date
math on it, and switch it back to the local time zone afterwards.
This avoids the possibility of having date math throw an exception,
and makes sure that 1 day equals 24 hours.

Reply via email to