Opened 12 years ago

Closed 5 years ago

#4543 closed Bugs (fixed)

ptime: year 2038 problem

Reported by: Roland Bock <rbock@…> Owned by: James E. King, III
Milestone: Boost 1.67.0 Component: date_time
Version: Boost 1.44.0 Severity: Problem
Keywords: Cc:

Description

At several locations in the code, the number of seconds, minutes, hours, etc is explicitly limited to the value range of long, for instance in posix_time/conversion.hpp:

  inline
  ptime from_time_t(std::time_t t)
  {
    ptime start(gregorian::date(1970,1,1));
    return start + seconds(static_cast<long>(t));
  }

As a result, for example -4260211200 is represented by some ptime in the year 1971, but it should be 1835.

Or, in other words Boost.DateTime has the year 2038 problem.

Regards,

Roland

Change History (15)

comment:1 by ookami1@…, 12 years ago

as a side note:

I wonder whether date_time could (or should) be brought fully in line with ISO 8601. Not yet supported is

  • day-of-week numbering 1-7
  • proleptic usage back to year 1 B.C.

Roland Bock's observation adds to this list.

cheers

Wolf Lammen

comment:2 by pjohnmeyer@…, 11 years ago

I am curious what the path forward is on this bug, which still exists in 1.48. I have implemented my own version of "from_time_t" that we use on our project that extends the useful life of the function significantly.

The most confusing part of this problem, in my mind, is that you can achieve valid and invalid times by performing essentially the same set of operations. See below:

  std::time_t theT = std::time_t(LONG_MAX) + std::time_t(100000);
  auto tm1 = boost::posix_time::from_time_t(theT);
  auto tm2 = boost::posix_time::from_time_t(LONG_MAX) + boost::posix_time::seconds(100000);
  auto tm3 = myproject::from_time_t(theT);

tm1 is 1901-Dec-15 00:32:31, because the from_time_t cast to long (which is 32-bits on my platform, MSVC) causes the positive value LONG_MAX + 100000 to be interpreted as a negative value.

tm2 and tm3 both evaluate, correctly, to 2038-Jan-20 07:00:47. tm2 at a glance does nothing mathematically different; it simply adds in the additional 100000 seconds after from_time_t is called.

Here is the implementation of myproject::from_time_t. Yes it has magic numbers that I calculated by working backwards from the inner workings of the posix_time code, and it doesn't address the full range of possible values of a 64-bit time_t. It does, however, extend the max value to 9,012,505,233,654 seconds since the epoch. The impacts this has elsewhere, however, I have not yet examined -- I know that, for example, converting extremely high values to a gregorian date will cause a bad year exception.

  boost::posix_time::ptime myproject::from_time_t(std::time_t time)
  {
    return boost::posix_time::ptime(
      static_cast<boost::posix_time::ptime::time_rep_type>(
        210866803200000000ll + (time * 1000000) )
  }

comment:3 by az_sw_dude, 10 years ago

This is a real issue, however, it goes beyond the implementation of this method. The seconds type itself has a limited range and is subject to this overflow. So this needs to be addressed more generally in the library.

comment:4 by az_sw_dude, 10 years ago

Milestone: Boost 1.44.0
Status: newassigned

comment:5 by Jim King <jim.king@…>, 7 years ago

I found that in time_resolution_traits the variable type being used is a boost::int32_t. I changed this to std::time_t and the problems went away. This did require rebuilding some things. I was able to simplify to_time_t and from_time_t down to:

  //! Function that converts a time_t into a ptime.
  inline
  ptime from_time_t(std::time_t t)
  {
    return ptime(gregorian::date(1970,1,1)) + seconds(t);
  }

  //! Function that converts a ptime into a time_t
  inline
  std::time_t to_time_t(const ptime& pt)
  {
    return (pt - ptime(gregorian::date(1970,1,1))).total_seconds();
  }

What I am uncertain of is the effect this has on any backwards compatibility or i/o conversions for streaming. Thoughts?

comment:6 by Jim King <jim.king@…>, 7 years ago

Here are the changes I made. They are not yet in boost 1.60 but I believe they should be considered:

root@dvm5:/usr/local/src# diff boost_1_60_0_b1/boost/date_time/time_resolution_traits.hpp boost_1_59_0/boost/date_time/time_resolution_traits.hpp 
12c12
< 
---
> #include <ctime>
71c71
<            typename var_type = boost::int32_t >
---
>            typename var_type = std::time_t >
root@dvm5:/usr/local/src# diff boost_1_60_0_b1/boost/date_time/posix_time/conversion.hpp boost_1_59_0/boost/date_time/posix_time/conversion.hpp 
12a13
> #include <boost/cstdint.hpp>
24d24
< 
29,30c29
<     ptime start(gregorian::date(1970,1,1));
<     return start + seconds(static_cast<long>(t));
---
>     return ptime(gregorian::date(1970,1,1)) + seconds(t);
35c34
<   std::time_t to_time_t(ptime pt)
---
>   std::time_t to_time_t(const ptime& pt)
37,38c36
<     time_duration dur = pt - ptime(gregorian::date(1970,1,1));
<     return std::time_t(dur.total_seconds());
---
>     return (pt - ptime(gregorian::date(1970,1,1))).total_seconds();

comment:7 by TMx, 7 years ago

We were also stumbling across that issue, and I would consider it a serious one. Since this is open for 6 years now, I wonder when is it planned to fix it? Will it be part of 1.61?

Thanks, Thomas

comment:8 by anonymous, 6 years ago

Hi,

Can any Boost date_time maintainer consider the above patch provided by Jim King. It also fixes the year 2038 issues I have when using to_time_t.

Cheers, Romain

comment:9 by jim.king@…, 6 years ago

https://github.com/boostorg/date_time/pull/35

I just realized there's no unit test that covers the original issue or the fix. Hopefully whomever is pulling in the fix into their module can add that.

comment:10 by anonymous, 6 years ago

#2818 is even older than this bug, but it's the same. Any chance to be fixed in this decade?

comment:11 by anonymous, 6 years ago

This may need to be brought to the attention of someone who organizes the boost project as a whole. This issue is serious and hasn't even been assigned to a milestone for 7 years.

comment:12 by Edward Diener, 6 years ago

I merged the PR into the 'develop' branch but it may not make it into Boost 1.64, which is in beta testing. The original date_time author has not been active in Boost for a while so others, including myself, are trying to pay attention to bug reports and PRs for date_time.

comment:13 by James E. King, III, 5 years ago

For folks who have commented on this issue in the past, the fix in 1.66.0 caused a serialization problem as the output was not properly versioned (no changes were made to accomodate the older 32-bit values), see https://github.com/boostorg/date_time/issues/56 for details.

comment:14 by James E. King, III, 5 years ago

Milestone: Boost 1.67.0
Owner: changed from az_sw_dude to James E. King, III
Status: assignednew

All known y2038 issues are resolved in 1.67.0 so I am marking it as the milestone. These are covered by a variety of other trac issues.

comment:15 by James E. King, III, 5 years ago

Resolution: fixed
Status: newclosed

Fix merged to master; resolved.

Note: See TracTickets for help on using tickets.