diff options
author | Andreas Heinisch <andreas.heinisch@yahoo.de> | 2021-03-23 10:54:14 +0100 |
---|---|---|
committer | Andreas Heinisch <andreas.heinisch@yahoo.de> | 2021-03-25 09:42:40 +0100 |
commit | ea61644abe9e7cd35cdb54452dac327782bbc402 (patch) | |
tree | 0bec03e2b405c54060d3c4425bad7e6428f83559 | |
parent | 89af24074e9adac4d005dcc322d81db09fc19f54 (diff) |
tdf#58745 - Detect end of month when extending a date list
Change-Id: Icaa64a493598dc4bb8f2d6d076ad4300e2e4dde6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112976
Tested-by: Jenkins
Reviewed-by: Andreas Heinisch <andreas.heinisch@yahoo.de>
-rw-r--r-- | include/tools/date.hxx | 5 | ||||
-rw-r--r-- | sc/inc/global.hxx | 1 | ||||
-rw-r--r-- | sc/qa/unit/ucalc.cxx | 16 | ||||
-rw-r--r-- | sc/source/core/data/table4.cxx | 23 | ||||
-rw-r--r-- | tools/qa/cppunit/test_date.cxx | 25 | ||||
-rw-r--r-- | tools/source/datetime/tdate.cxx | 11 |
6 files changed, 77 insertions, 4 deletions
diff --git a/include/tools/date.hxx b/include/tools/date.hxx index cd69d16b10b6..6179d637e8ba 100644 --- a/include/tools/date.hxx +++ b/include/tools/date.hxx @@ -188,6 +188,9 @@ public: depending on month/year) */ bool IsValidDate() const; + // Returns true, if the date is the end of the month, false otherwise. + bool IsEndOfMonth() const; + /** Normalize date, invalid day or month values are adapted such that they carry over to the next month or/and year, for example 1999-02-32 becomes 1999-03-04, 1999-13-01 becomes 2000-01-01, 1999-13-42 becomes @@ -239,6 +242,8 @@ public: static sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear ); /// Semantically identical to IsValidDate() member method. static bool IsValidDate( sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear ); + /// Semantically identical to IsEndOfMonth() member method. + static bool IsEndOfMonth(sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear); /// Semantically identical to Normalize() member method. static bool Normalize( sal_uInt16 & rDay, sal_uInt16 & rMonth, sal_Int16 & rYear ); diff --git a/sc/inc/global.hxx b/sc/inc/global.hxx index 3a1429acb0bc..50041b37b323 100644 --- a/sc/inc/global.hxx +++ b/sc/inc/global.hxx @@ -344,6 +344,7 @@ enum FillDateCmd FILL_DAY, FILL_WEEKDAY, FILL_MONTH, + FILL_END_OF_MONTH, FILL_YEAR }; diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index ec599ad7a42d..ec424f97f1d9 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -4963,6 +4963,22 @@ void Test::testAutoFill() CPPUNIT_ASSERT_EQUAL( OUString("2012-10-31"), m_pDoc->GetString( 0, 104, 0 ) ); // Clear column A for a new test. + clearRange(m_pDoc, ScRange(0, 0, 0, 0, MAXROW, 0)); + m_pDoc->SetRowHidden(0, MAXROW, 0, false); // Show all rows. + + m_pDoc->SetString(0, 100, 0, "2019-10-31"); + m_pDoc->SetString(0, 101, 0, "2019-11-30"); + m_pDoc->SetString(0, 102, 0, "2019-12-31"); + m_pDoc->Fill(0, 100, 0, 102, nullptr, aMarkData, 3, FILL_TO_BOTTOM, FILL_AUTO); + + // tdf#58745, Without the fix in place, this test would have failed with + // - Expected: 2020-01-31 + // - Actual : 2019-01-11 + CPPUNIT_ASSERT_EQUAL(OUString("2020-01-31"), m_pDoc->GetString(0, 103, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("2020-02-29"), m_pDoc->GetString(0, 104, 0)); + CPPUNIT_ASSERT_EQUAL(OUString("2020-03-31"), m_pDoc->GetString(0, 105, 0)); + + // Clear column A for a new test. clearRange(m_pDoc, ScRange(0,0,0,0,MAXROW,0)); m_pDoc->SetRowHidden(0, MAXROW, 0, false); // Show all rows. diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx index 02e6c1c31d83..e6c29a5a00e7 100644 --- a/sc/source/core/data/table4.cxx +++ b/sc/source/core/data/table4.cxx @@ -535,7 +535,12 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, tools::Long nDDiff = aDate2.GetDay() - static_cast<tools::Long>(aDate1.GetDay()); tools::Long nMDiff = aDate2.GetMonth() - static_cast<tools::Long>(aDate1.GetMonth()); tools::Long nYDiff = aDate2.GetYear() - static_cast<tools::Long>(aDate1.GetYear()); - if ( nDDiff ) + if (nMDiff && aDate1.IsEndOfMonth() && aDate2.IsEndOfMonth()) + { + eType = FILL_END_OF_MONTH; + nCmpInc = nMDiff + 12 * nYDiff; + } + else if (nDDiff) { eType = FILL_DAY; nCmpInc = aDate2 - aDate1; @@ -566,7 +571,8 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, nDDiff = aDate2.GetDay() - static_cast<tools::Long>(aDate1.GetDay()); nMDiff = aDate2.GetMonth() - static_cast<tools::Long>(aDate1.GetMonth()); nYDiff = aDate2.GetYear() - static_cast<tools::Long>(aDate1.GetYear()); - if (nDDiff || ( nMDiff + 12 * nYDiff != nCmpInc )) + if ((nDDiff && !aDate1.IsEndOfMonth() && !aDate2.IsEndOfMonth()) + || (nMDiff + 12 * nYDiff != nCmpInc)) bVal = false; } aDate1 = aDate2; @@ -578,7 +584,8 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, } if (bVal) { - if ( eType == FILL_MONTH && ( nCmpInc % 12 == 0 ) ) + if ((eType == FILL_MONTH || eType == FILL_END_OF_MONTH) + && (nCmpInc % 12 == 0)) { eType = FILL_YEAR; nCmpInc /= 12; @@ -1514,6 +1521,7 @@ void ScTable::IncDate(double& rVal, sal_uInt16& nDayOfMonth, double nStep, FillD } break; case FILL_MONTH: + case FILL_END_OF_MONTH: { if ( nDayOfMonth == 0 ) nDayOfMonth = aDate.GetDay(); // init @@ -1549,7 +1557,14 @@ void ScTable::IncDate(double& rVal, sal_uInt16& nDayOfMonth, double nStep, FillD { aDate.SetMonth(static_cast<sal_uInt16>(nMonth)); aDate.SetYear(static_cast<sal_uInt16>(nYear)); - aDate.SetDay( std::min( Date::GetDaysInMonth( nMonth, nYear), nDayOfMonth ) ); + if (eCmd == FILL_END_OF_MONTH) + { + aDate.SetDay(Date::GetDaysInMonth(nMonth, nYear)); + } + else + { + aDate.SetDay(std::min(Date::GetDaysInMonth(nMonth, nYear), nDayOfMonth)); + } } } break; diff --git a/tools/qa/cppunit/test_date.cxx b/tools/qa/cppunit/test_date.cxx index 9a243cce504c..e11270e6a299 100644 --- a/tools/qa/cppunit/test_date.cxx +++ b/tools/qa/cppunit/test_date.cxx @@ -26,6 +26,7 @@ public: void testGetDayOfWeek(); void testGetDaysInMonth(); void testIsBetween(); + void testIsEndOfMonth(); CPPUNIT_TEST_SUITE(DateTest); CPPUNIT_TEST(testDate); @@ -37,6 +38,7 @@ public: CPPUNIT_TEST(testGetDayOfWeek); CPPUNIT_TEST(testGetDaysInMonth); CPPUNIT_TEST(testIsBetween); + CPPUNIT_TEST(testIsEndOfMonth); CPPUNIT_TEST_SUITE_END(); }; @@ -533,6 +535,29 @@ void DateTest::testIsBetween() CPPUNIT_ASSERT(aDate.IsBetween(Date(1, 1, 2018), Date(1, 12, 2018))); } +void DateTest::testIsEndOfMonth() +{ + { + Date aDate(31, 12, 2000); + CPPUNIT_ASSERT(aDate.IsEndOfMonth()); + } + + { + Date aDate(30, 12, 2000); + CPPUNIT_ASSERT(!aDate.IsEndOfMonth()); + } + + { + Date aDate(29, 2, 2000); + CPPUNIT_ASSERT(aDate.IsEndOfMonth()); + } + + { + Date aDate(28, 2, 2000); + CPPUNIT_ASSERT(!aDate.IsEndOfMonth()); + } +} + CPPUNIT_TEST_SUITE_REGISTRATION(DateTest); } diff --git a/tools/source/datetime/tdate.cxx b/tools/source/datetime/tdate.cxx index a38fb8e986c3..979611333813 100644 --- a/tools/source/datetime/tdate.cxx +++ b/tools/source/datetime/tdate.cxx @@ -452,6 +452,17 @@ bool Date::IsValidDate( sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear ) return true; } +bool Date::IsEndOfMonth() const +{ + return IsEndOfMonth(GetDay(), GetMonth(), GetYear()); +} + +//static +bool Date::IsEndOfMonth(sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear) +{ + return IsValidDate(nDay, nMonth, nYear) && ImplDaysInMonth(nMonth, nYear) == nDay; +} + void Date::Normalize() { sal_uInt16 nDay = GetDay(); |