From: Vadim Zeitlin Date: Thu, 4 Oct 2012 22:48:30 +0000 (+0000) Subject: Fix bugs in the recently added wxDateTime::DiffAsDateSpan(). X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/f4370376b6e5a3df8b3f2cd1637483554af2fa4a Fix bugs in the recently added wxDateTime::DiffAsDateSpan(). Correct the test for negative spans less than a month and use the correct month for computing the number of days in it. Also add unit tests for problematic cases. Closes #14704. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72616 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/src/common/datetime.cpp b/src/common/datetime.cpp index 462347d7d6..05ceb27e0d 100644 --- a/src/common/datetime.cpp +++ b/src/common/datetime.cpp @@ -1612,25 +1612,34 @@ wxDateSpan wxDateTime::DiffAsDateSpan(const wxDateTime& dt) const inv = -1; int y = GetYear() - dt.GetYear(); + int m = GetMonth() - dt.GetMonth(); + int d = GetDay() - dt.GetDay(); // If month diff is negative, dt is the year before, so decrease year // and set month diff to its inverse, e.g. January - December should be 1, // not -11. - int m = GetMonth() - dt.GetMonth(); - if ( m * inv < 0 ) + if ( m * inv < 0 || (m == 0 && d * inv < 0)) { m += inv * MONTHS_IN_YEAR; y -= inv; } - // Same logic for days as for months above. Use number of days in month - // from the month which end date we're crossing. - int d = GetDay() - dt.GetDay(); + // Same logic for days as for months above. if ( d * inv < 0 ) { - d += inv * wxDateTime::GetNumberOfDays( - inv > 0 ? dt.GetMonth() : GetMonth(), - inv > 0 ? dt.GetYear() : GetMonth()); + // Use number of days in month from the month which end date we're + // crossing. That is month before this for positive diff, and this + // month for negative diff. + // If we're on january and using previous month, we get december + // previous year, but don't care, december has same amount of days + // every year. + wxDateTime::Month monthfordays = GetMonth(); + if (inv > 0 && monthfordays == wxDateTime::Jan) + monthfordays = wxDateTime::Dec; + else if (inv > 0) + monthfordays = static_cast(monthfordays - 1); + + d += inv * wxDateTime::GetNumberOfDays(monthfordays, GetYear()); m -= inv; } diff --git a/tests/datetime/datetimetest.cpp b/tests/datetime/datetimetest.cpp index 00a76af0ea..e317c4707d 100644 --- a/tests/datetime/datetimetest.cpp +++ b/tests/datetime/datetimetest.cpp @@ -1214,6 +1214,31 @@ void DateTimeTestCase::TestTimeArithmetics() CPPUNIT_ASSERT_EQUAL( dt1, dt2 + 2*span ); CPPUNIT_ASSERT_EQUAL( span, dt1.DiffAsDateSpan(dt) ); } + + // More date span arithmetics tests + wxDateTime dtd1(5, wxDateTime::Jun, 1998); + wxDateTime dtd2(6, wxDateTime::Aug, 1999); + + // All parts in dtd2 is after dtd1 + CPPUNIT_ASSERT_EQUAL( wxDateSpan(1, 2, 0, 1), dtd2.DiffAsDateSpan(dtd1) ); + + // Year and month after, day earlier, so no full month + // Jul has 31 days, so it's 31 - 5 + 4 = 30, or 4w 2d + dtd2.Set(4, wxDateTime::Aug, 1999); + CPPUNIT_ASSERT_EQUAL( wxDateSpan(1, 1, 4, 2), dtd2.DiffAsDateSpan(dtd1) ); + + // Year and day after, month earlier, so no full year, but same day diff as + // first example + dtd2.Set(6, wxDateTime::May, 1999); + CPPUNIT_ASSERT_EQUAL( wxDateSpan(0, 11, 0, 1), dtd2.DiffAsDateSpan(dtd1) ); + + // Year after, month and day earlier, so no full month and no full year + // April has 30 days, so it's 30 - 5 + 4 = 29, or 4w 1d + dtd2.Set(4, wxDateTime::May, 1999); + CPPUNIT_ASSERT_EQUAL( wxDateSpan(0, 10, 4, 1), dtd2.DiffAsDateSpan(dtd1) ); + + // And a reverse. Now we should use days in Jun (again 30 => 4w 1d) + CPPUNIT_ASSERT_EQUAL( wxDateSpan(0, -10, -4, -1), dtd1.DiffAsDateSpan(dtd2) ); } void DateTimeTestCase::TestDSTBug()