diff options
author | Eike Rathke <erack@redhat.com> | 2021-09-29 23:14:18 +0200 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2021-09-30 02:04:01 +0200 |
commit | ebc454ad4eb1f4cd4d84a7db367bb71a457c4e5c (patch) | |
tree | c516e035c0fb686b59a86ff8d1f21706c0d85bc6 /svl/source/numbers | |
parent | 18e49d2b998ba69d5363d25d285ee6fd188a698d (diff) |
Resolves: tdf#144697 Format out-of-bounds date(+time) as #FMT error
i.e. < -32768-01-01 or > 32767-12-31
They couldn't be input or stored as proleptic Gregorian in file
formats anyway.
Additionally in i18npool handle the absolute year values casting
conversion int32 <-> int16 where era 0 BCE year 32768 is fielded as
-32768 but still is a valid year for our proleptic Gregorian, so
it isn't displayed as --32768.
Change-Id: Ifdd482f07e04c2a4296fd0556bbef7f1d3e15676
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/122835
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
Diffstat (limited to 'svl/source/numbers')
-rw-r--r-- | svl/source/numbers/zforlist.cxx | 20 | ||||
-rw-r--r-- | svl/source/numbers/zformat.cxx | 32 |
2 files changed, 47 insertions, 5 deletions
diff --git a/svl/source/numbers/zforlist.cxx b/svl/source/numbers/zforlist.cxx index 755dda187b9b..185dc97f12fa 100644 --- a/svl/source/numbers/zforlist.cxx +++ b/svl/source/numbers/zforlist.cxx @@ -1713,6 +1713,7 @@ void SvNumberFormatter::GetInputLineString(const double& fOutNumber, { pFormat = GetFormatEntry( nKey ); } + assert(pFormat); if (pFormat) { if ( eType == SvNumFormatType::TIME && pFormat->GetFormatPrecision() ) @@ -1720,7 +1721,24 @@ void SvNumberFormatter::GetInputLineString(const double& fOutNumber, ChangeStandardPrec(INPUTSTRING_PRECISION); bPrecChanged = true; } - pFormat->GetOutputString(fOutNumber, sOutString, &pColor); + const bool bOk = pFormat->GetOutputString(fOutNumber, sOutString, &pColor); + + // The #FMT error string must not be used for input as it would lead to + // data loss. This can happen for at least date(+time). Fall back to a + // last resort of plain number in the locale the formatter was + // contructed with. + if (!bOk && eType != SvNumFormatType::NUMBER && sOutString == ImpSvNumberformatScan::sErrStr) + { + pFormat = GetFormatEntry(ZF_STANDARD); + assert(pFormat); + if (pFormat) + { + ChangeStandardPrec(INPUTSTRING_PRECISION); + bPrecChanged = true; + pFormat->GetOutputString(fOutNumber, sOutString, &pColor); + } + } + assert(sOutString != ImpSvNumberformatScan::sErrStr); } if (bPrecChanged) { diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx index 0f618e75ca02..53eb8181c2d6 100644 --- a/svl/source/numbers/zformat.cxx +++ b/svl/source/numbers/zformat.cxx @@ -3647,6 +3647,24 @@ static bool lcl_isSignedYear( const CalendarWrapper& rCal, const ImpSvNumFor& rN rCal.getUniqueID() == GREGORIAN && !lcl_hasEra( rNumFor ); } +/* XXX: if needed this could be stripped from rEpochStart and diff adding and + * moved to tools' DateTime to be reused elsewhere. */ +static bool lcl_getValidDate( const DateTime& rNullDate, const DateTime& rEpochStart, double& fNumber ) +{ + static const DateTime aCE( Date(1,1,1)); + static const DateTime aMin( Date(1,1, SAL_MIN_INT16)); + static const DateTime aMax( Date(31,12, SAL_MAX_INT16), tools::Time(23,59,59, tools::Time::nanoSecPerSec - 1)); + static const double fMin = aMin - aCE; + static const double fMax = aMax - aCE; + // Value must be representable in our tools::Date proleptic Gregorian + // calendar as well. + const double fOff = (rNullDate - aCE) + fNumber; + // Add diff between epochs to serial date number. + const double fDiff = rNullDate - rEpochStart; + fNumber += fDiff; + return fMin <= fOff && fOff <= fMax; +} + bool SvNumberformat::ImpGetDateOutput(double fNumber, sal_uInt16 nIx, OUStringBuffer& sBuff) @@ -3655,8 +3673,11 @@ bool SvNumberformat::ImpGetDateOutput(double fNumber, bool bRes = false; CalendarWrapper& rCal = GetCal(); - double fDiff = DateTime(rScan.GetNullDate()) - rCal.getEpochStart(); - fNumber += fDiff; + if (!lcl_getValidDate( rScan.GetNullDate(), rCal.getEpochStart(), fNumber)) + { + sBuff = ImpSvNumberformatScan::sErrStr; + return false; + } rCal.setLocalDateTime( fNumber ); int nUseMonthCase = 0; // Not decided yet OUString aOrgCalendar; // empty => not changed yet @@ -3922,8 +3943,11 @@ bool SvNumberformat::ImpGetDateTimeOutput(double fNumber, bool bRes = false; CalendarWrapper& rCal = GetCal(); - double fDiff = DateTime(rScan.GetNullDate()) - rCal.getEpochStart(); - fNumber += fDiff; + if (!lcl_getValidDate( rScan.GetNullDate(), rCal.getEpochStart(), fNumber)) + { + sBuff = ImpSvNumberformatScan::sErrStr; + return false; + } const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); bool bInputLine; |