Skip to content

Commit

Permalink
Fix support for dates after 2038 in wxDateTime with 64-bit time_t
Browse files Browse the repository at this point in the history
Use CRT for dates > 2038 in wxDateTime::Set() if time_t is 64-bit.

See wxWidgets#24464.

Co-authored-by: Vadim Zeitlin <vadim@wxwidgets.org>
  • Loading branch information
lanurmi and vadz committed Apr 28, 2024
1 parent 4457e59 commit 2c47603
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 10 deletions.
1 change: 1 addition & 0 deletions docs/changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ Changes in behaviour which may result in build errors
All:

- Add support for "%F" format specifier to wxDateTime (#24173).
- Support dates > 2038 if time_t is 64-bit (Lauri Nurmi, #24464).
- Restore possible ABI incompatibility with wx < 3.2.3 in wxString.
- Set request and response for wxEVT_WEBREQUEST_DATA events (#24416).

Expand Down
10 changes: 6 additions & 4 deletions include/wx/datetime.h
Original file line number Diff line number Diff line change
Expand Up @@ -1621,9 +1621,11 @@ class WXDLLIMPEXP_BASE wxDateTimeWorkDays : public wxDateTimeHolidayAuthority

inline bool wxDateTime::IsInStdRange() const
{
// currently we don't know what is the real type of time_t so prefer to err
// on the safe side and limit it to 32 bit values which is safe everywhere
return m_time >= 0l && (m_time / TIME_T_FACTOR) < wxINT32_MAX;
// if sizeof(time_t) is greater than 32 bits, we assume it
// is safe to return values exceeding wxINT32_MAX

return m_time >= 0l &&
( (sizeof(time_t) > 4 ) || ( (m_time / TIME_T_FACTOR) < wxINT32_MAX) );
}

/* static */
Expand Down Expand Up @@ -1730,7 +1732,7 @@ inline time_t wxDateTime::GetTicks() const
return (time_t)-1;
}

return (time_t)((m_time / (long)TIME_T_FACTOR).ToLong()) + WX_TIME_BASE_OFFSET;
return (time_t)((m_time / TIME_T_FACTOR).GetValue()) + WX_TIME_BASE_OFFSET;
}

inline bool wxDateTime::SetToLastWeekDay(WeekDay weekday,
Expand Down
12 changes: 9 additions & 3 deletions src/common/datetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
* algorithms limitations, only dates from Nov 24, 4714BC are handled
*
* 3. standard ANSI C functions are used to do time calculations whenever
* possible, i.e. when the date is in the range Jan 1, 1970 to 2038
* possible, i.e. when the date is in time_t range, i.e. after Jan 1, 1970
* and, for 32-bit time_t, before 2038.
*
* 4. otherwise, the calculations are done by converting the date to/from JDN
* first (the range limitation mentioned above comes from here: the
Expand Down Expand Up @@ -1257,13 +1258,18 @@ wxDateTime& wxDateTime::Set(wxDateTime_t day,
wxDATETIME_CHECK( (0 < day) && (day <= GetNumberOfDays(month, year)),
wxT("Invalid date in wxDateTime::Set()") );

// the range of time_t type (inclusive)
// Check if we can use the standard library implementation: this only works
// for the dates representable by time_t, i.e. after the beginning of the
// Epoch and, for 32-bit time_t, before 2038 (for 64-bit time_t, the range
// is unlimited and while we can't be sure that the standard library works
// for the dates in the distant future, we are not going to do better
// ourselves neither, so let it handle them).
static const int yearMinInRange = 1970;
static const int yearMaxInRange = 2037;

// test only the year instead of testing for the exact end of the Unix
// time_t range - it doesn't bring anything to do more precise checks
if ( year >= yearMinInRange && year <= yearMaxInRange )
if ( year >= yearMinInRange && (sizeof(time_t) > 4 || year <= yearMaxInRange) )
{
// use the standard library version if the date is in range - this is
// probably more efficient than our code
Expand Down
22 changes: 19 additions & 3 deletions tests/datetime/datetimetest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ struct Date
wxDateTime::wxDateTime_t hour, min, sec;
double jdn;
wxDateTime::WeekDay wday;
time_t gmticks;
wxInt64 gmticks;

void Init(const wxDateTime::Tm& tm)
{
Expand Down Expand Up @@ -184,7 +184,8 @@ static const Date testDates[] =
{ 8, wxDateTime::Feb, 2036, 00, 00, 00, 2464731.5, wxDateTime::Fri, -1 },
{ 1, wxDateTime::Jan, 2037, 00, 00, 00, 2465059.5, wxDateTime::Thu, -1 },
{ 1, wxDateTime::Jan, 2038, 00, 00, 00, 2465424.5, wxDateTime::Fri, -1 },
{ 21, wxDateTime::Jan, 2222, 00, 00, 00, 2532648.5, wxDateTime::Mon, -1 },
{ 1, wxDateTime::Jan, 2044, 00, 00, 00, 2467615.5, wxDateTime::Fri, 2335219200LL },
{ 21, wxDateTime::Jan, 2222, 00, 00, 00, 2532648.5, wxDateTime::Mon, 7954070400LL },
{ 29, wxDateTime::May, 1976, 12, 00, 00, 2442928.0, wxDateTime::Sat, 202219200 },
{ 29, wxDateTime::Feb, 1976, 00, 00, 00, 2442837.5, wxDateTime::Sun, 194400000 },
{ 1, wxDateTime::Jan, 1900, 12, 00, 00, 2415021.0, wxDateTime::Mon, -1 },
Expand Down Expand Up @@ -1072,7 +1073,7 @@ void DateTimeTestCase::TestTimeTicks()

INFO("n=" << n);

time_t ticks = (dt.GetValue() / 1000).ToLong();
wxInt64 ticks = (dt.GetValue() / 1000).GetValue();
CHECK( d.gmticks == ticks );
}
}
Expand Down Expand Up @@ -1111,6 +1112,12 @@ void DateTimeTestCase::TestParseRFC822()
true
},

{
"Tue, 12 Apr 2044 10:48:30 -0500",
{ 12, wxDateTime::Apr, 2044, 15, 48, 30 },
true
},

{
"Sat, 18 Dec 1999 10:48:30 G", // military time zone
{ 18, wxDateTime::Dec, 1999, 17, 48, 30 },
Expand Down Expand Up @@ -1283,6 +1290,7 @@ void DateTimeTestCase::TestDateParse()
{ "31/03/06", { 31, wxDateTime::Mar, 6 }, true, "" },
{ "31/03/2006", { 31, wxDateTime::Mar, 2006 }, true, "" },
{ "Thu 20 Jun 2019", { 20, wxDateTime::Jun, 2019 }, true, "" },
{ "Sun 20 Jun 2049", { 20, wxDateTime::Jun, 2049 }, true, "" },
{ "20 Jun 2019 Thu", { 20, wxDateTime::Jun, 2019 }, true, "" },
{ "Dec sixth 2017", { 6, wxDateTime::Dec, 2017 }, true, "" },

Expand Down Expand Up @@ -1435,6 +1443,14 @@ void DateTimeTestCase::TestDateTimeParse()
false
},

{
"Sun 20 Jun 2049 07:40:00 PM",
{ 20, wxDateTime::Jun, 2049, 19, 40, 0 },
true,
"",
false
},

{
"2010-01-04 14:30",
{ 4, wxDateTime::Jan, 2010, 14, 30, 0 },
Expand Down

0 comments on commit 2c47603

Please sign in to comment.