diff options
author | Eike Rathke <erack@redhat.com> | 2012-01-10 16:42:01 +0100 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2012-01-11 13:18:45 +0100 |
commit | 8298a4741d95034f65c648dddfae081f44cf9455 (patch) | |
tree | 64edd4bc021b92f2f1ae81c9b93a06e6bd4b4d4d | |
parent | 958cdbdcf5e35c04e259a69e972684060f1b3d12 (diff) |
strict date recognition using locale's separator and ISO 8601
- Removed separators '-', '.' and '/' working in all combinations in all
locales forcing a date even for 23/12.99 (if locale has DMY order)
* Only the locale's date separator is accepted, plus '-' if the input may
represent an ISO 8601 date yyyy-mm-dd, check is lax though on minimum
digits, y-m-d is also accepted.
* Additionally, accept yy-month-dd or dd-month-yy with month name. Year must
be <1 or >31, 2-digit year magic for values 0,32..99 is applied, or has to
be prefixed with leading zero.
-rw-r--r-- | svl/source/numbers/zforfind.cxx | 69 | ||||
-rw-r--r-- | svl/source/numbers/zforfind.hxx | 19 |
2 files changed, 71 insertions, 17 deletions
diff --git a/svl/source/numbers/zforfind.cxx b/svl/source/numbers/zforfind.cxx index 3df9232c3b56..3cf61e17dc2e 100644 --- a/svl/source/numbers/zforfind.cxx +++ b/svl/source/numbers/zforfind.cxx @@ -145,6 +145,7 @@ void ImpSvNumberInputScan::Reset() nMatchedAllStrings = nMatchedVirgin; nMayBeIso8601 = 0; nTimezonePos = 0; + nMayBeMonthDate = 0; } @@ -995,6 +996,44 @@ bool ImpSvNumberInputScan::MayBeIso8601() } //--------------------------------------------------------------------------- + +bool ImpSvNumberInputScan::MayBeMonthDate() +{ + if (nMayBeMonthDate == 0) + { + nMayBeMonthDate = 1; + if (nAnzNums >= 2 && nNums[1] < nAnzStrings) + { + // "-Jan-" + const String& rM = sStrArray[nNums[0]+1]; + if (rM.Len() >= 3 && rM.GetChar(0) == '-' && rM.GetChar( rM.Len()-1) == '-') + { + // Check year length assuming at least 3 digits (including + // leading zero). Two digit years 1..31 are out of luck here + // and may be taken as day of month. + bool bYear1 = (sStrArray[nNums[0]].Len() >= 3); + bool bYear2 = (sStrArray[nNums[1]].Len() >= 3); + sal_Int32 n; + bool bDay1 = (!bYear1 && (n = sStrArray[nNums[0]].ToInt32()) >= 1 && n <= 31); + bool bDay2 = (!bYear2 && (n = sStrArray[nNums[1]].ToInt32()) >= 1 && n <= 31); + if (bDay1 && !bDay2) + nMayBeMonthDate = 2; // dd-month-yy + else if (!bDay1 && bDay2) + nMayBeMonthDate = 3; // yy-month-dd + else if (bDay1 && bDay2) + { + if (bYear1 && !bYear2) + nMayBeMonthDate = 3; // yy-month-dd + else if (!bYear1 && bYear2) + nMayBeMonthDate = 2; // dd-month-yy + } + } + } + } + return nMayBeMonthDate > 1; +} + +//--------------------------------------------------------------------------- // GetDateRef bool ImpSvNumberInputScan::GetDateRef( double& fDays, sal_uInt16& nCounter, @@ -1283,10 +1322,11 @@ input for the following reasons: } break; case 2: // month in the middle (10 Jan 94) + { pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 ); - switch (DateFmt) + DateFormat eDF = (MayBeMonthDate() ? (nMayBeMonthDate == 2 ? DMY : YMD) : DateFmt); + switch (eDF) { - case MDY: // yes, "10-Jan-94" is valid case DMY: pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) ); @@ -1299,7 +1339,8 @@ input for the following reasons: res = false; break; } - break; + } + break; default: // else, e.g. month at the end (94 10 Jan) res = false; break; @@ -1687,13 +1728,10 @@ bool ImpSvNumberInputScan::ScanMidString( const String& rString, const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData(); const String& rDate = pFormatter->GetDateSep(); - const String& rTime = pLoc->getTimeSep(); - sal_Unicode cTime = rTime.GetChar(0); SkipBlanks(rString, nPos); - if ( SkipString(rDate, rString, nPos) // 10., 10-, 10/ - || ((cTime != '.') && SkipChar('.', rString, nPos)) // TRICKY: - || ((cTime != '/') && SkipChar('/', rString, nPos)) // short boolean - || ((cTime != '-') && SkipChar('-', rString, nPos)) ) // evaluation! + if (SkipString( rDate, rString, nPos) // 10. 10- 10/ + || ((MayBeIso8601() || MayBeMonthDate()) + && SkipChar( '-', rString, nPos))) { if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type && eScannedType != NUMBERFORMAT_DATE) // except date @@ -1752,6 +1790,7 @@ bool ImpSvNumberInputScan::ScanMidString( const String& rString, SkipBlanks(rString, nPos); } + const String& rTime = pLoc->getTimeSep(); if ( SkipString(rTime, rString, nPos) ) // time separator? { if (nDecPos) // already . => maybe error @@ -1945,7 +1984,6 @@ bool ImpSvNumberInputScan::ScanEndString( const String& rString, } const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData(); - const String& rDate = pFormatter->GetDateSep(); const String& rTime = pLoc->getTimeSep(); if ( SkipString(rTime, rString, nPos) ) // 10: { @@ -1968,11 +2006,10 @@ bool ImpSvNumberInputScan::ScanEndString( const String& rString, nTimePos = nAnzStrings; } - sal_Unicode cTime = rTime.GetChar(0); - if ( SkipString(rDate, rString, nPos) // 10., 10-, 10/ - || ((cTime != '.') && SkipChar('.', rString, nPos)) // TRICKY: - || ((cTime != '/') && SkipChar('/', rString, nPos)) // short boolean - || ((cTime != '-') && SkipChar('-', rString, nPos)) ) // evaluation! + const String& rDate = pFormatter->GetDateSep(); + if (SkipString( rDate, rString, nPos) // 10. 10- 10/ + || ((MayBeIso8601() || MayBeMonthDate()) + && SkipChar( '-', rString, nPos))) { if (eScannedType != NUMBERFORMAT_UNDEFINED && eScannedType != NUMBERFORMAT_DATE) // already another type @@ -2535,8 +2572,6 @@ void ImpSvNumberInputScan::ChangeIntl() { sal_Unicode cDecSep = pFormatter->GetNumDecimalSep().GetChar(0); bDecSepInDateSeps = ( cDecSep == '-' || - cDecSep == '/' || - cDecSep == '.' || cDecSep == pFormatter->GetDateSep().GetChar(0) ); bTextInitialized = false; aUpperCurrSymbol.Erase(); diff --git a/svl/source/numbers/zforfind.hxx b/svl/source/numbers/zforfind.hxx index 02e08d4b31a3..5d6cb85e00c5 100644 --- a/svl/source/numbers/zforfind.hxx +++ b/svl/source/numbers/zforfind.hxx @@ -78,6 +78,11 @@ public: */ bool MayBeIso8601(); + /** Whether input may be a dd-month-yy format, with month name, not + number. + */ + bool MayBeMonthDate(); + private: SvNumberFormatter* pFormatter; String* pUpperMonthText; // Array of month names, uppercase @@ -136,14 +141,28 @@ private: sal_uInt16 nTimezonePos; // Index of timezone separator (+1) /** State of ISO 8601 detection. + 0:= don't know yet 1:= no 2:= yes, <=2 digits in year 3:= yes, 3 digits in year 4:= yes, >=4 digits in year + + @see MayBeIso8601() */ sal_uInt8 nMayBeIso8601; + /** State of dd-month-yy or yy-month-dd detection, with month name. + + 0:= don't know yet + 1:= no + 2:= yes, dd-month-yy + 3:= yes, yy-month-dd + + @see MayBeMonthDate() + */ + sal_uInt8 nMayBeMonthDate; + #ifdef _ZFORFIND_CXX // methods private to implementation void Reset(); // Reset all variables before start of analysis |