diff options
author | Eike Rathke <erack@redhat.com> | 2018-05-15 19:36:52 +0200 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2018-05-23 13:56:23 +0200 |
commit | a16a53deab649b2165d998ef43567346f83cb4bf (patch) | |
tree | f17c3a7562c70da5cb2c143cd7f6813ab2d8cd63 /basic | |
parent | db2924ef296b4308ba45077b591da9d9ab4c427b (diff) |
Resolves: tdf#117612 truncate DateAdd("m",...) to last day of month
... instead of resulting in error because of roll-over not being set.
Fallout from
commit 6d424f07701bf26d8fb173563b567d5f097c33e2
CommitDate: Tue May 2 23:12:34 2017 +0200
Replace mouth-painted "inaccurate around leap year" rollover algorithm
that does stricter checking but DateAdd() needs a lax checking
with truncate to last day of month.
(cherry picked from commit 40c9a129e5a53e6eadfe8ca80c98ccf7eda957f9)
Conflicts:
basic/source/runtime/methods.cxx
Backported.
Change-Id: I9d6f95ad3ac38257d492019bd621070491e98e76
Reviewed-on: https://gerrit.libreoffice.org/54421
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
(cherry picked from commit 07a0748243fed290771b8805398b0ca7a52369f7)
Diffstat (limited to 'basic')
-rw-r--r-- | basic/source/inc/date.hxx | 9 | ||||
-rw-r--r-- | basic/source/runtime/methods.cxx | 39 | ||||
-rw-r--r-- | basic/source/runtime/methods1.cxx | 20 | ||||
-rw-r--r-- | basic/source/sbx/sbxscan.cxx | 2 |
4 files changed, 41 insertions, 29 deletions
diff --git a/basic/source/inc/date.hxx b/basic/source/inc/date.hxx index 4b28f1d66b02..c0cfd66a5cf7 100644 --- a/basic/source/inc/date.hxx +++ b/basic/source/inc/date.hxx @@ -24,7 +24,14 @@ #include <com/sun/star/util/Time.hpp> #include <com/sun/star/util/DateTime.hpp> -bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, bool bUseTwoDigitYear, bool bRollOver, double& rdRet ); +enum class SbDateCorrection +{ + None, + RollOver, + TruncateToMonth +}; + +bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, bool bUseTwoDigitYear, SbDateCorrection eCorr, double& rdRet ); double implTimeSerial( sal_Int16 nHour, sal_Int16 nMinute, sal_Int16 nSecond); bool implDateTimeSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, sal_Int16 nHour, sal_Int16 nMinute, sal_Int16 nSecond, diff --git a/basic/source/runtime/methods.cxx b/basic/source/runtime/methods.cxx index 4a5aaa39a98b..07044ac5e6c5 100644 --- a/basic/source/runtime/methods.cxx +++ b/basic/source/runtime/methods.cxx @@ -1733,7 +1733,7 @@ css::util::Date SbxDateToUNODate( const SbxValue* const pVal ) void SbxDateFromUNODate( SbxValue *pVal, const css::util::Date& aUnoDate) { double dDate; - if( implDateSerial( aUnoDate.Year, aUnoDate.Month, aUnoDate.Day, false, false, dDate ) ) + if( implDateSerial( aUnoDate.Year, aUnoDate.Month, aUnoDate.Day, false, SbDateCorrection::None, dDate ) ) { pVal->PutDate( dDate ); } @@ -1962,8 +1962,9 @@ void SbRtl_CDateFromIso(StarBASIC *, SbxArray & rPar, bool) } double dDate; - if (!implDateSerial( (sal_Int16)(nSign * aYearStr.toInt32()), - (sal_Int16)aMonthStr.toInt32(), (sal_Int16)aDayStr.toInt32(), bUseTwoDigitYear, false, dDate )) + if (!implDateSerial( static_cast<sal_Int16>(nSign * aYearStr.toInt32()), + static_cast<sal_Int16>(aMonthStr.toInt32()), static_cast<sal_Int16>(aDayStr.toInt32()), + bUseTwoDigitYear, SbDateCorrection::None, dDate )) break; rPar.Get(0)->PutDate( dDate ); @@ -1992,7 +1993,7 @@ void SbRtl_DateSerial(StarBASIC *, SbxArray & rPar, bool) sal_Int16 nDay = rPar.Get(3)->GetInteger(); double dDate; - if( implDateSerial( nYear, nMonth, nDay, true, true, dDate ) ) + if( implDateSerial( nYear, nMonth, nDay, true, SbDateCorrection::RollOver, dDate ) ) { rPar.Get(0)->PutDate( dDate ); } @@ -4557,7 +4558,7 @@ sal_Int16 implGetDateYear( double aDate ) } bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, - bool bUseTwoDigitYear, bool bRollOver, double& rdRet ) + bool bUseTwoDigitYear, SbDateCorrection eCorr, double& rdRet ) { // XXX NOTE: For VBA years<0 are invalid and years in the range 0..29 and // 30..99 can not be input as they are 2-digit for 2000..2029 and @@ -4620,14 +4621,14 @@ bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, * documentation would need to be adapted. As is, the DateSerial() runtime * function works as dumb as documented.. (except that the resulting date * is checked for validity now and not just day<=31 and month<=12). - * If change wanted then simply remove overriding bRollOver here and adapt + * If change wanted then simply remove overriding RollOver here and adapt * documentation.*/ #if HAVE_FEATURE_SCRIPTING - if (!SbiRuntime::isVBAEnabled()) - bRollOver = false; + if (eCorr == SbDateCorrection::RollOver && !SbiRuntime::isVBAEnabled()) + eCorr = SbDateCorrection::None; #endif - if (nYear == 0 || (!bRollOver && (nAddMonths || nAddDays || !aCurDate.IsValidDate()))) + if (nYear == 0 || (eCorr == SbDateCorrection::None && (nAddMonths || nAddDays || !aCurDate.IsValidDate()))) { #if HAVE_FEATURE_SCRIPTING StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); @@ -4635,13 +4636,29 @@ bool implDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, return false; } - if (bRollOver) + if (eCorr != SbDateCorrection::None) { aCurDate.Normalize(); if (nAddMonths) aCurDate.AddMonths( nAddMonths); if (nAddDays) aCurDate.AddDays( nAddDays); + if (eCorr == SbDateCorrection::TruncateToMonth && aCurDate.GetMonth() != nMonth) + { + if (aCurDate.GetYear() == SAL_MAX_INT16 && nMonth == 12) + { + // Roll over and back not possible, hard max. + aCurDate.SetMonth(12); + aCurDate.SetDay(31); + } + else + { + aCurDate.SetMonth(nMonth); + aCurDate.SetDay(1); + aCurDate.AddMonths(1); + aCurDate.AddDays(-1); + } + } } long nDiffDays = GetDayDiff( aCurDate ); @@ -4664,7 +4681,7 @@ bool implDateTimeSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, double& rdRet ) { double dDate; - if(!implDateSerial(nYear, nMonth, nDay, false/*bUseTwoDigitYear*/, false/*bRollOver*/, dDate)) + if(!implDateSerial(nYear, nMonth, nDay, false/*bUseTwoDigitYear*/, SbDateCorrection::None, dDate)) return false; rdRet += dDate + implTimeSerial(nHour, nMinute, nSecond); return true; diff --git a/basic/source/runtime/methods1.cxx b/basic/source/runtime/methods1.cxx index f6d404dd548d..6921fe639f87 100644 --- a/basic/source/runtime/methods1.cxx +++ b/basic/source/runtime/methods1.cxx @@ -1898,7 +1898,7 @@ void SbRtl_DateAdd(StarBASIC *, SbxArray & rPar, bool) nTargetYear16 = limitDate( nTargetYear, nMonth, nDay ); /* TODO: should the result be error if the date was limited? It never was. */ nTargetMonth = nMonth; - bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, true, dNewDate ); + bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, SbDateCorrection::TruncateToMonth, dNewDate ); break; } case INTERVAL_Q: @@ -1943,26 +1943,14 @@ void SbRtl_DateAdd(StarBASIC *, SbxArray & rPar, bool) } nTargetYear16 = limitDate( nTargetYear, nTargetMonth, nDay ); /* TODO: should the result be error if the date was limited? It never was. */ - bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, true, dNewDate ); + bOk = implDateSerial( nTargetYear16, nTargetMonth, nDay, false, SbDateCorrection::TruncateToMonth, dNewDate ); break; } default: break; } if( bOk ) - { - // Overflow? - sal_Int16 nNewYear, nNewMonth, nNewDay; - implGetDayMonthYear( nNewYear, nNewMonth, nNewDay, dNewDate ); - sal_Int16 nCorrectionDay = nDay; - while( nNewMonth > nTargetMonth ) - { - nCorrectionDay--; - implDateSerial( nTargetYear16, nTargetMonth, nCorrectionDay, false, true, dNewDate ); - implGetDayMonthYear( nNewYear, nNewMonth, nNewDay, dNewDate ); - } dNewDate += dHoursMinutesSeconds; - } } rPar.Get(0)->PutDate( dNewDate ); @@ -2147,7 +2135,7 @@ double implGetDateOfFirstDayInFirstWeek nFirstWeekMinDays = 7; // vbFirstFourDays double dBaseDate; - implDateSerial( nYear, 1, 1, false, false, dBaseDate ); + implDateSerial( nYear, 1, 1, false, SbDateCorrection::None, dBaseDate ); sal_Int16 nWeekDay0101 = implGetWeekDay( dBaseDate ); sal_Int16 nDayDiff = nWeekDay0101 - nFirstDay; @@ -2207,7 +2195,7 @@ void SbRtl_DatePart(StarBASIC *, SbxArray & rPar, bool) { sal_Int16 nYear = implGetDateYear( dDate ); double dBaseDate; - implDateSerial( nYear, 1, 1, false, false, dBaseDate ); + implDateSerial( nYear, 1, 1, false, SbDateCorrection::None, dBaseDate ); nRet = 1 + sal_Int32( dDate - dBaseDate ); break; } diff --git a/basic/source/sbx/sbxscan.cxx b/basic/source/sbx/sbxscan.cxx index 55539079680e..acee4a5759d3 100644 --- a/basic/source/sbx/sbxscan.cxx +++ b/basic/source/sbx/sbxscan.cxx @@ -771,7 +771,7 @@ void SbxValue::Format( OUString& rRes, const OUString* pFmt ) const { sal_Int16 nYear = implGetDateYear( nNumber ); double dBaseDate; - implDateSerial( nYear, 1, 1, true, false, dBaseDate ); + implDateSerial( nYear, 1, 1, true, SbDateCorrection::None, dBaseDate ); sal_Int32 nYear32 = 1 + sal_Int32( nNumber - dBaseDate ); rRes = OUString::number(nYear32); } |