I have a collection of unix timestamps I am converting to boost (1.65.1) dates but the conversions seem to break down when they get too far in the future. Anything around 2040 and beyond seems to be wrapping in some way back to post 1900.
Given the following code...
{
std::time_t t = 1558220400;
boost::gregorian::date date = boost::posix_time::from_time_t(t).date();
std::cout << "Date: " << date << std::endl;
}
{
std::time_t t = 2145500000;
boost::gregorian::date date = boost::posix_time::from_time_t(t).date();
std::cout << "Date: " << date << std::endl;
}
{
std::time_t t = 2500000000;
boost::gregorian::date date = boost::posix_time::from_time_t(t).date();
std::cout << "Date: " << date << std::endl;
}
... I get the following output...
Date: 2019-May-18
Date: 2037-Dec-27
Date: 1913-Feb-13
... however I am expecting the following output...
Expected output:
Date: 2019-May-18
Date: 2037-Dec-27
Date: 2049-Mar-22
Is there something I am doing wrong here?
It appears that you're experiencing the Year 2038 problem.
The largest number representable by 32 bit signed integer is 2'147'483'647. 2'147'483'647 seconds since 00:00:00 UTC on 1st of January 1970 (the UNIX epoch) is 03:14:07 UTC on 19th of January 2038. Any UNIX time after that is unrepresentable using a 32 bit signed integer.
Either std::time_t
on the system is 32 bits, or it is converted into 32 bits inside the boost library. You can see from the source that boost converts the input into long
using static_cast
(and still does in version 1.70). long
is 32 bits for example on windows, even on 64 bit architectures. It is 64 bits on many other systems such as 64 bit Linux.
In C++20 this can now look like:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
{
std::time_t t = 1558220400;
auto date = floor<days>(system_clock::from_time_t(t));
std::cout << "Date: " << date << '\n';
}
{
std::time_t t = 2145500000;
auto date = floor<days>(system_clock::from_time_t(t));
std::cout << "Date: " << date << '\n';
}
{
std::time_t t = 2500000000;
auto date = floor<days>(system_clock::from_time_t(t));
std::cout << "Date: " << date << '\n';
}
}
Output:
Date: 2019-05-18
Date: 2037-12-27
Date: 2049-03-22
If your time_t
is 32 bits, then the above isn't quite sufficient to fix the problem. In that case, you must avoid the C API completely. This looks like:
{
auto t = 1558220400;
auto date = floor<days>(sys_seconds{seconds{t}});
std::cout << "Date: " << date << '\n';
}
{
auto t = 2145500000;
auto date = floor<days>(sys_seconds{seconds{t}});
std::cout << "Date: " << date << '\n';
}
{
auto t = 2500000000;
auto date = floor<days>(sys_seconds{seconds{t}});
std::cout << "Date: " << date << '\n';
}
If your vendor isn't shipping this part of C++20 yet, a free, open-source preview that works with C++11/14/17 is available.1
Just add:
#include "date/date.h"
...
using namespace date;
1 Full disclosure: I am the lead author of this library. I am not pursuing any financial gain from this effort. But sometimes people get grumpy if I don't fully disclose this information.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With