in reply to Re^3: Date::Manip and daylight savings
in thread Date::Manip and daylight savings

Date::Manip defines a day as 24 hours which DOES lead to unexpected results... but it DOES lead to unambiguous and correct results.

For those interested, DateTime has no such false equivalences. DateTime can

On the other hand,

The passage I quoted makes it sound like Date::Manip doesn't correctly handle some or all of those. Please let me know if it can.

Replies are listed 'Best First'.
Re^5: Date::Manip and daylight savings
by Anonymous Monk on Nov 07, 2011 at 22:03 UTC
    Add one day, which is not necessarily the same as adding 24 hours (which it can also do).

    From DateTime docs.

    When math crosses a daylight saving boundary, a single day may have more or less than 24 hours.

    For example, 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 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".

    If all this makes your head hurt, there is a simple alternative. 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. Of course, this may not always be desirable, so caveat user!

      you will produce an invalid local time, and therefore an exception will be thrown.

      As it should. Returning an invalid local time (2003-04-06T02:00:00) would be wrong.

      Are you implying that Date::Manip behaves differently?

      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.

      That's bad advice. It's just a very expensive way of doing $dt->add( hours => 24 );, which is very different than adding a day.

      use feature qw( say );; use DateTime; my $dt = DateTime->new( year => 2003, month => 4, day => 5, hour => 2, time_zone => 'America/Chicago', ); $dt->set_time_zone('UTC'); $dt->add( days => 1 ); $dt->set_time_zone('America/Chicago'); say $dt; # ERROR: 2003-04-06T03:00:00

      My question went unanswered. Is Date::Manip only able to add 24 hours, or is it also able to add one day?

        Here's the deal with Date::Manip.

        There are some differences between how DateTime and Date::Manip do calculations. I don't know that I agree that either is 'right' or 'wrong' because so much of it is subject to opinion... however, let me see if I can detail the differences.

        Date::Manip can add a year, and most of the time it's result is the same as DateTime. One difference is that 2004-02-29 plus one year is 2005-02-28. With DateTime, the result is 2005-03-01.

        Date::Manip can add a month. 2004-03-31 plus one month is 2004-04-30. With DateTime, the result is 2004-05-01.

        Date::Manip can add a minute, but unlike DateTime, I don't use leap seconds, so a minute is always 60 seconds. Unlike leap years, variable length months, and daylight saving time transitions, leap seconds are not something the people use in a day-to-day usage, and since I was trying to do operations as people did them, I chose to ignore leap seconds. Date::Manip also does not use fractional seconds. They are never used, except they are allowed in parsing where they are truncated and ignored.

        The relationship 1 day = 24 hours has been in Date::Manip all along, but I am working on changing that. Since adding true support for daylight saving time, that relationship isn't acceptable. However I'm not sure of all the details of how I want to change it, so I won't go into any more detail than what I said earlier in this thread. One thing though is that I won't throw an exception (or return an empty date). If you have a valid date and a valid amount of time, I'll try to figure out what is intuitively expected and return that, and so in the example above, I'll probably fall back on the 1 day = 24 hours so that I can return a valid date.