Opened 13 years ago

Last modified 6 years ago

#3109 new Bugs

time_duration::total_seconds() - overflow

Reported by: ioni@… Owned by: az_sw_dude
Milestone: To Be Determined Component: date_time
Version: Boost 1.41.0 Severity: Problem
Keywords: year 2038 problem Cc:

Description

time_duration::total_seconds() overflow value

minimal sample (based on boost example) #include <string> #include <boost/date_time/local_time/local_time.hpp>

int main() {

using namespace boost::gregorian; using namespace boost::local_time; using namespace boost::posix_time;

date in_date(2039, 10, 04); time_duration td(12,14,32); std::string z("PST-8PDT,M4.1.0,M10.1.0"); time_zone_ptr zone(new posix_time_zone(z)); local_date_time my_time(in_date, td, zone, local_date_time::NOT_DATE_TIME_ON_ERROR); std::cout << my_time << std::endl; ptime time_t_epoch( date(1970,1,1) ); std::cout << time_t_epoch << std::endl; time_duration diff = my_time.utc_time() - time_t_epoch; std::cout << "Seconds diff: " << diff.total_seconds() << std::endl; return 0;

}

Change History (4)

comment:1 by rehor@…, 13 years ago

Version: Boost 1.39.0Boost 1.41.0

platform: MSVC 8, Windows XP Boost 1.41

time_duration::total_seconds should be returning 64bit int instead of 32bit int. All underlying code is correct, only the return type of time_duration::total_seconds() is only a 32bit int, which is not wide enough for time durations lasting several decades or a century. When changed to 64bit int, total_seconds() works as expected. The problem possibly applies to other total_* methods as well.

time_duration d = 
    ptime(boost::gregorian::date(2010,1,1)) 
  - ptime(boost::gregorian::date(1899,12,30));

unsigned long long s = d.total_seconds(); // returns a negative int 

Proposed fix: time_duration.hpp

    //! Returns total number of seconds truncating any fractional seconds
    tick_type total_seconds() const	//changed type from sec_type to tick_type
    {
      return static_cast<tick_type>(ticks() / ticks_per_second());
    }

comment:2 by Klemens Schindler, 11 years ago

This problem still applies to Boost version 1.47 (I didn't check even newer versions)

The following code:

    using namespace boost::posix_time;
    using namespace boost::gregorian;
    using namespace boost::local_time;

    local_date_time now(local_sec_clock::local_time(time_zone_ptr()));
    local_date_time baseADTime( date(1601, 1, 1), hours(0), time_zone_ptr(), local_date_time::NOT_DATE_TIME_ON_ERROR);
    time_duration timeInterval(now.utc_time() - baseADTime.utc_time());

    cout << "BaseTime: " << baseADTime << endl;
    cout << "Time: " << now << endl;
    cout << "MicroSeconds: " << timeInterval.total_microseconds() << endl;
    cout << "MilliSeconds: " << timeInterval.total_milliseconds() << endl;
    cout << "Seconds: " << timeInterval.total_seconds() << endl;

produces the following output:

BaseTime: 1601-Jan-01 00:00:00 UTC
Time: 2012-Feb-08 12:36:54 UTC
MicroSeconds: 12973178214000000
MilliSeconds: 12973178214000
Seconds: 88276326

In case you're wondering why it would be interesting to calculate the time interval between 01-01-1601 and now: the time representation in Microsoft Active Directory uses a time representation based on the time between 1601 and now.

It is at least counterintuitive that types with a higher resolution/precision are able to store larger intervals. According to the documentation documentation, all "total_x" methods should return the same type, that doesn't seem to be the case.

It is probably possible to use type traits to set the internal representation, but this is somewhat complex to do. (Thanks to Andrei Korostelev for pointing out this possibility). In any case as far as I know it cannot be done in an obvious/self-explanatory way.

Another proposed solution would be to add a template parameter to total_seconds and similar methods so you can explicitly specify the representation type. For example:

int_fast64_t numSeconds = timeInterval.total_seconds<int_fast64_t>()

This way a user explicitly states what he wants and will not run into surprises.

comment:3 by anonymous, 6 years ago

This problem still exists in Boost version 1.61. It may also cause confusion in calculating total milliseconds from epoch(1/1/1970).

comment:3 by anonymous, 6 years ago

This problem still exists in Boost version 1.61. It may also cause confusion in calculating total milliseconds from epoch(1/1/1970).

Note: See TracTickets for help on using tickets.