Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost local_date_time math wrong?

I'm using Boost's datetime library in my project. I was very happy when I discovered that it has time duration types for hours, days, months, years, etc, and they change their value based on what you're adding them to (i.e. adding 1 month advances the month part of the date, it doesn't just add 30 days or somesuch). I thought this property held for the days type, but I decided to test it before I put it into production...

local_date_time t1(date(2010, 3, 14), hours(1), easternTime, false); // 1am on DST transition date

{
    CPPUNIT_ASSERT_EQUAL(greg_year(2010), t1.local_time().date().year());
    CPPUNIT_ASSERT_EQUAL(greg_month(3), t1.local_time().date().month());
    CPPUNIT_ASSERT_EQUAL(greg_day(14), t1.local_time().date().day());
    CPPUNIT_ASSERT_EQUAL(1L, t1.local_time().time_of_day().hours());
    CPPUNIT_ASSERT_EQUAL(0L, t1.local_time().time_of_day().minutes());
    CPPUNIT_ASSERT_EQUAL(0L, t1.local_time().time_of_day().seconds());
}

t1 += days(1); // the time in EST should now be 1am on the 15th
{
    CPPUNIT_ASSERT_EQUAL(greg_year(2010), t1.local_time().date().year());
    CPPUNIT_ASSERT_EQUAL(greg_month(3), t1.local_time().date().month());
    CPPUNIT_ASSERT_EQUAL(greg_day(15), t1.local_time().date().day());
    CPPUNIT_ASSERT_EQUAL(1L, t1.local_time().time_of_day().hours()); // fails, returns 2
    CPPUNIT_ASSERT_EQUAL(0L, t1.local_time().time_of_day().minutes());
    CPPUNIT_ASSERT_EQUAL(0L, t1.local_time().time_of_day().seconds());
}

Above you'll see my CPPUNIT unit test. It fails at the indicated line with 2, which is what I would expect if days() merely added 24 hours, instead of 1 logical day (since the DST transition causes 2010-03-14 to be 23 hours long in EST).

Am I doing something wrong? Is this a bug? Did I just completely misunderstand the design goal of the library with respect to this sort of math?

like image 879
rmeador Avatar asked Feb 11 '10 15:02

rmeador


1 Answers

I think the problem is in the asker's conception of what a day is. He wants it to be a 'date' day here, rather than 24 hours, but that is not a reasonable thing to ask for.

If working in local time, one is bound to encounter peculiar effects. For example, what do you expect to happen if, in a timezone that puts clocks forward from 1am to 2am, if your local time 'add date day' calculation should set the (non existent) 1.30am on the relevant Sunday morning?

A time calculation has got to move forward 24 hours - it must operate on the underlying UTC time.

To make the 'jump one day' calculation as described, work with Boost's date type, and only add in the time-of-day as the final action.

The business of being able to advance a month is quite different, because, unlike a day, a calendar month has no specific meaning as a duration. And it causes troubles too: if you advance one calendar month from 31st January, and then go back one calendar month, what date do you end up with?

like image 67
willw Avatar answered Sep 24 '22 15:09

willw