chart2/source/view/axes/DateHelper.cxx | 6 - sax/qa/cppunit/test_converter.cxx | 9 +- sax/source/tools/converter.cxx | 19 +++- sc/source/core/tool/interpr2.cxx | 2 sd/source/ui/annotations/annotationmanager.cxx | 2 sfx2/source/doc/docfile.cxx | 2 sfx2/source/doc/oleprops.cxx | 2 svl/source/items/dateitem.cxx | 2 svtools/source/contnr/templwin.cxx | 2 svtools/source/control/calendar.cxx | 8 - sw/source/core/fields/docufld.cxx | 2 sw/source/ui/docvw/SidebarWin.cxx | 2 tools/inc/tools/date.hxx | 6 + tools/source/datetime/tdate.cxx | 111 +++++++++++++++++++++++-- tools/source/inet/inetmsg.cxx | 2 vcl/source/control/field2.cxx | 2 xmloff/source/core/xmluconv.cxx | 11 ++ 17 files changed, 158 insertions(+), 32 deletions(-)
New commits: commit 7613359985a89a42417a746bcdbb25f072784733 Author: Eike Rathke <er...@redhat.com> Date: Wed Nov 30 02:05:25 2011 +0100 handle dates with year < 1000 * Read dates with years consisting of less than 4 digits. ISO 8601 specifies that years are to be written with a minimum of 4 digits. However, be lenient in what we accept. * Write years < 1000 with leading zeros to comply with ISO 8601 YYYY. diff --git a/sax/qa/cppunit/test_converter.cxx b/sax/qa/cppunit/test_converter.cxx index 923c7eb..17d1303 100644 --- a/sax/qa/cppunit/test_converter.cxx +++ b/sax/qa/cppunit/test_converter.cxx @@ -215,8 +215,13 @@ void ConverterTest::testDateTime() doTest( util::DateTime(0, 0, 0, 24, 1, 1, 333) /*(0, 0, 0, 0, 2, 1, 333)*/, "0333-01-01T24:00:00"/*, "0333-01-02T00:00:00"*/ ); - doTestDateTimeF( "+0001-01-01T00:00:00" ); // invalid: ^+ - doTestDateTimeF( "1-01-01T00:00:00" ); // invalid: < 4 Y + // A leading ^+ is NOT invalid, ISO 8601 specifies this for explicit AD/CE. + doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1), + "+0001-01-01T00:00:00", "0001-01-01T00:00:00" ); + // While ISO 8601 specifies a minimum of 4 year digits we are lenient in + // what we accept. + doTest( util::DateTime(0, 0, 0, 0, 1, 1, 1), + "1-01-01T00:00:00", "0001-01-01T00:00:00" ); doTestDateTimeF( "0001-1-01T00:00:00" ); // invalid: < 2 M doTestDateTimeF( "0001-01-1T00:00:00" ); // invalid: < 2 D doTestDateTimeF( "0001-01-01T0:00:00" ); // invalid: < 2 H diff --git a/sax/source/tools/converter.cxx b/sax/source/tools/converter.cxx index b1629c8..0c0779b 100644 --- a/sax/source/tools/converter.cxx +++ b/sax/source/tools/converter.cxx @@ -1345,15 +1345,26 @@ bool Converter::convertDateOrDateTime( const ::rtl::OUString string = rString.trim().toAsciiUpperCase(); sal_Int32 nPos(0); - if ((string.getLength() > nPos) && (sal_Unicode('-') == string[nPos])) + if (string.getLength() > nPos) { - //Negative Number - ++nPos; + if (sal_Unicode('-') == string[nPos]) + { + //Negative Number + ++nPos; + } + else if (sal_Unicode('+') == string[nPos]) + { + //Positive Number, explicit AD/CE + ++nPos; + } } sal_Int32 nYear(0); { - bSuccess = readDateTimeComponent(string, nPos, nYear, 4, false); + // While ISO 8601 specifies years with a minimum of 4 digits, be + // leninent in what we accept for years < 1000. One digit is acceptable + // if the remainders match. + bSuccess = readDateTimeComponent(string, nPos, nYear, 1, false); bSuccess &= (0 < nYear); bSuccess &= (nPos < string.getLength()); // not last token } diff --git a/xmloff/source/core/xmluconv.cxx b/xmloff/source/core/xmluconv.cxx index 5ea85f1..6ceb885 100644 --- a/xmloff/source/core/xmluconv.cxx +++ b/xmloff/source/core/xmluconv.cxx @@ -436,9 +436,16 @@ void SvXMLUnitConverter::convertDateTime( OUStringBuffer& rBuffer, aDate += 1; } } - rBuffer.append( sal_Int32( aDate.GetYear())); + sal_uInt16 nTemp = aDate.GetYear(); + if (nTemp < 1000) + rBuffer.append( sal_Unicode('0')); + if (nTemp < 100) + rBuffer.append( sal_Unicode('0')); + if (nTemp < 10) + rBuffer.append( sal_Unicode('0')); + rBuffer.append( sal_Int32( nTemp)); rBuffer.append( sal_Unicode('-')); - sal_uInt16 nTemp = aDate.GetMonth(); + nTemp = aDate.GetMonth(); if (nTemp < 10) rBuffer.append( sal_Unicode('0')); rBuffer.append( sal_Int32( nTemp)); commit 07a7b2937a9427b2feb3307804ec0f527091bb92 Author: Eike Rathke <er...@redhat.com> Date: Wed Nov 30 02:05:24 2011 +0100 fixed fdo#40363 freeze chart wizard with non-gregorian date Use the newly introduced Date::Normalize() instead of a never ending while(!date.IsValid()) diff --git a/chart2/source/view/axes/DateHelper.cxx b/chart2/source/view/axes/DateHelper.cxx index 6749e74..247e0f6 100644 --- a/chart2/source/view/axes/DateHelper.cxx +++ b/chart2/source/view/axes/DateHelper.cxx @@ -73,8 +73,7 @@ Date DateHelper::GetDateSomeMonthsAway( const Date& rD, long nMonthDistance ) nNewMonth += 12; aRet.SetMonth( sal_uInt16(nNewMonth) ); aRet.SetYear( sal_uInt16(nNewYear) ); - while(!aRet.IsValidAndGregorian()) - aRet--; + aRet.Normalize(); return aRet; } @@ -82,8 +81,7 @@ Date DateHelper::GetDateSomeYearsAway( const Date& rD, long nYearDistance ) { Date aRet(rD); aRet.SetYear( static_cast<sal_uInt16>(rD.GetYear()+nYearDistance) ); - while(!aRet.IsValidAndGregorian()) - aRet--; + aRet.Normalize(); return aRet; } commit 6619955e72c1c2f29a32e82478d19147c0d7610a Author: Eike Rathke <er...@redhat.com> Date: Wed Nov 30 02:05:23 2011 +0100 introduced Date::IsValidDate() and Date::Normalize() + IsValidDate() checks only day and month regarding the year, not Gregorian cut-off date as now does IsValidAndGregorian(). + Normalize() carries over invalid day and month values to next months and years. * All methods that return or internally use a day count now internally normalize the date values, without modifying the actual Date instance. So, if the date is not valid you may get unexpected results. * Previously, a date with month>12 would had accessed the days-of-month array out of bounds on all such methods. So you would had gotten unexpected results anyway.. * Affected methods are: GetDayOfYear() GetWeekOfYear() GetDaysInMonth() static DateToDays() diff --git a/tools/source/datetime/tdate.cxx b/tools/source/datetime/tdate.cxx index 06b0bc4..5deef52 100644 --- a/tools/source/datetime/tdate.cxx +++ b/tools/source/datetime/tdate.cxx @@ -60,6 +60,8 @@ inline sal_Bool ImpIsLeapYear( sal_uInt16 nYear ) // ----------------------------------------------------------------------- +// All callers must have sanitized or normalized month and year values! + inline sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear ) { if ( nMonth != 2 ) @@ -79,6 +81,8 @@ long Date::DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear ) { long nDays; + Normalize( nDay, nMonth, nYear); + nDays = ((sal_uIntPtr)nYear-1) * 365; nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400); for( sal_uInt16 i = 1; i < nMonth; i++ ) @@ -203,9 +207,13 @@ DayOfWeek Date::GetDayOfWeek() const sal_uInt16 Date::GetDayOfYear() const { - sal_uInt16 nDay = GetDay(); - for( sal_uInt16 i = 1; i < GetMonth(); i++ ) - nDay = nDay + ::DaysInMonth( i, GetYear() ); // += yields a warning on MSVC, so don't use it + sal_uInt16 nDay = GetDay(); + sal_uInt16 nMonth = GetMonth(); + sal_uInt16 nYear = GetYear(); + Normalize( nDay, nMonth, nYear); + + for( sal_uInt16 i = 1; i < nMonth; i++ ) + nDay = nDay + ::DaysInMonth( i, nYear ); // += yields a warning on MSVC, so don't use it return nDay; } @@ -305,7 +313,12 @@ sal_uInt16 Date::GetWeekOfYear( DayOfWeek eStartDay, sal_uInt16 Date::GetDaysInMonth() const { - return DaysInMonth( GetMonth(), GetYear() ); + sal_uInt16 nDay = GetDay(); + sal_uInt16 nMonth = GetMonth(); + sal_uInt16 nYear = GetYear(); + Normalize( nDay, nMonth, nYear); + + return DaysInMonth( nMonth, nYear ); } // ----------------------------------------------------------------------- @@ -343,6 +356,94 @@ sal_Bool Date::IsValidAndGregorian() const // ----------------------------------------------------------------------- +bool Date::IsValidDate() const +{ + return IsValidDate( GetDay(), GetMonth(), GetYear()); +} + +// ----------------------------------------------------------------------- + +//static +bool Date::IsValidDate( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear ) +{ + if ( !nMonth || (nMonth > 12) ) + return false; + if ( !nDay || (nDay > DaysInMonth( nMonth, nYear )) ) + return false; + return true; +} + +// ----------------------------------------------------------------------- + +bool Date::Normalize() +{ + sal_uInt16 nDay = GetDay(); + sal_uInt16 nMonth = GetMonth(); + sal_uInt16 nYear = GetYear(); + + if (!Normalize( nDay, nMonth, nYear)) + return false; + + SetDay( nDay); + SetMonth( nMonth); + SetYear( nYear); + + return true; +} + +// ----------------------------------------------------------------------- + +//static +bool Date::Normalize( sal_uInt16 & rDay, sal_uInt16 & rMonth, sal_uInt16 & rYear ) +{ + if (IsValidDate( rDay, rMonth, rYear)) + return false; + + if (rMonth > 12) + { + rYear += rMonth / 12; + rMonth = rMonth % 12; + } + if (!rMonth) + { + if (!rYear) + { + rYear = 0; + rMonth = 1; + if (rDay > 31) + rDay -= 31; + else + rDay = 1; + } + else + { + --rYear; + rMonth = 12; + } + } + sal_uInt16 nDays; + while (rDay > (nDays = DaysInMonth( rMonth, rYear))) + { + rDay -= nDays; + if (rMonth < 12) + ++rMonth; + else + { + ++rYear; + rMonth = 1; + } + } + if (rYear > 9999) + { + rDay = 31; + rMonth = 12; + rYear = 9999; + } + return true; +} + +// ----------------------------------------------------------------------- + Date& Date::operator +=( long nDays ) { sal_uInt16 nDay; commit dca69d5bb2d0e542de26624dd9f71fb87e1533f2 Author: Eike Rathke <er...@redhat.com> Date: Wed Nov 30 02:05:22 2011 +0100 renamed Date::IsValid() to IsValidAndGregorian() to prevent misassumptions Once smaller than 1582-10-15 decrementing a Date will not produce a valid date. diff --git a/chart2/source/view/axes/DateHelper.cxx b/chart2/source/view/axes/DateHelper.cxx index 142dd60..6749e74 100644 --- a/chart2/source/view/axes/DateHelper.cxx +++ b/chart2/source/view/axes/DateHelper.cxx @@ -73,7 +73,7 @@ Date DateHelper::GetDateSomeMonthsAway( const Date& rD, long nMonthDistance ) nNewMonth += 12; aRet.SetMonth( sal_uInt16(nNewMonth) ); aRet.SetYear( sal_uInt16(nNewYear) ); - while(!aRet.IsValid()) + while(!aRet.IsValidAndGregorian()) aRet--; return aRet; } @@ -82,7 +82,7 @@ Date DateHelper::GetDateSomeYearsAway( const Date& rD, long nYearDistance ) { Date aRet(rD); aRet.SetYear( static_cast<sal_uInt16>(rD.GetYear()+nYearDistance) ); - while(!aRet.IsValid()) + while(!aRet.IsValidAndGregorian()) aRet--; return aRet; } diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx index be38e1f..ef42258 100644 --- a/sc/source/core/tool/interpr2.cxx +++ b/sc/source/core/tool/interpr2.cxx @@ -93,7 +93,7 @@ double ScInterpreter::GetDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int1 Date aDate( nD, nM, nY); if (!bStrict) aDate += nDay - 1; - if (aDate.IsValid()) + if (aDate.IsValidAndGregorian()) return (double) (aDate - *(pFormatter->GetNullDate())); else { diff --git a/sd/source/ui/annotations/annotationmanager.cxx b/sd/source/ui/annotations/annotationmanager.cxx index 772a428..625ecd4 100644 --- a/sd/source/ui/annotations/annotationmanager.cxx +++ b/sd/source/ui/annotations/annotationmanager.cxx @@ -175,7 +175,7 @@ OUString getAnnotationDateTimeString( const Reference< XAnnotation >& xAnnotatio if (aDate == Date(Date()-1)) sRet = sRet + String(SdResId(STR_ANNOTATION_YESTERDAY)); else - if (aDate.IsValid() ) + if (aDate.IsValidAndGregorian() ) sRet = sRet + rLocalData.getDate(aDate); Time aTime( aDateTime.Hours, aDateTime.Minutes, aDateTime.Seconds, aDateTime.HundredthSeconds ); diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx index ab3cbfc..097eba9 100644 --- a/sfx2/source/doc/docfile.cxx +++ b/sfx2/source/doc/docfile.cxx @@ -2969,7 +2969,7 @@ void SfxMedium::SetExpired_Impl( const DateTime& rDateTime ) sal_Bool SfxMedium::IsExpired() const { - return pImp->aExpireTime.IsValid() && pImp->aExpireTime < DateTime(); + return pImp->aExpireTime.IsValidAndGregorian() && pImp->aExpireTime < DateTime(); } //---------------------------------------------------------------- diff --git a/sfx2/source/doc/oleprops.cxx b/sfx2/source/doc/oleprops.cxx index b7d56b0..f42ed87 100644 --- a/sfx2/source/doc/oleprops.cxx +++ b/sfx2/source/doc/oleprops.cxx @@ -634,7 +634,7 @@ void SfxOleFileTimeProperty::ImplSave( SvStream& rStrm ) // invalid time stamp is not converted to UTC // heuristic to detect editing durations (which we assume to be < 1 year): // check only the year, not the entire date - if( aDateTimeUtc.IsValid() + if( aDateTimeUtc.IsValidAndGregorian() && aDateTimeUtc.GetYear() != TIMESTAMP_INVALID_DATETIME.GetYear() ) { aDateTimeUtc.ConvertToUTC(); } diff --git a/svl/source/items/dateitem.cxx b/svl/source/items/dateitem.cxx index 1df6b62..accd1cf 100644 --- a/svl/source/items/dateitem.cxx +++ b/svl/source/items/dateitem.cxx @@ -148,7 +148,7 @@ SfxItemPresentation SfxDateTimeItem::GetPresentation ) const { DBG_CHKTHIS(SfxDateTimeItem, 0); - if (aDateTime.IsValid()) + if (aDateTime.IsValidAndGregorian()) if (pIntlWrapper) { rText = pIntlWrapper->getLocaleData()->getDate(aDateTime); diff --git a/svtools/source/contnr/templwin.cxx b/svtools/source/contnr/templwin.cxx index 3792826..c2daae8 100644 --- a/svtools/source/contnr/templwin.cxx +++ b/svtools/source/contnr/templwin.cxx @@ -164,7 +164,7 @@ void lcl_insertDateTimeEntry(SvtExtendedMultiLineEdit_Impl* i_pEditWin, DateTime( Date( i_rUDT.Day, i_rUDT.Month, i_rUDT.Year ), Time( i_rUDT.Hours, i_rUDT.Minutes, i_rUDT.Seconds, i_rUDT.HundredthSeconds ) ); - if ( aToolsDT.IsValid() ) + if ( aToolsDT.IsValidAndGregorian() ) { LocaleDataWrapper aLocaleWrapper( ::comphelper::getProcessServiceFactory(), diff --git a/svtools/source/control/calendar.cxx b/svtools/source/control/calendar.cxx index 7b4bf57..4ff76c3 100644 --- a/svtools/source/control/calendar.cxx +++ b/svtools/source/control/calendar.cxx @@ -1974,7 +1974,7 @@ void Calendar::Select() void Calendar::SelectDate( const Date& rDate, sal_Bool bSelect ) { - if ( !rDate.IsValid() ) + if ( !rDate.IsValidAndGregorian() ) return; Table* pOldSel; @@ -2037,7 +2037,7 @@ Date Calendar::GetSelectDate( sal_uLong nIndex ) const void Calendar::SetCurDate( const Date& rNewDate ) { - if ( !rNewDate.IsValid() ) + if ( !rNewDate.IsValidAndGregorian() ) return; if ( maCurDate != rNewDate ) @@ -2638,9 +2638,9 @@ sal_Bool CalendarField::ShowDropDown( sal_Bool bShow ) Calendar* pCalendar = GetCalendar(); Date aDate = GetDate(); - if ( IsEmptyDate() || !aDate.IsValid() ) + if ( IsEmptyDate() || !aDate.IsValidAndGregorian() ) { - if ( maDefaultDate.IsValid() ) + if ( maDefaultDate.IsValidAndGregorian() ) aDate = maDefaultDate; else aDate = Date(); diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx index f950016..74366ea 100644 --- a/sw/source/core/fields/docufld.cxx +++ b/sw/source/core/fields/docufld.cxx @@ -994,7 +994,7 @@ String SwDocInfoFieldType::Expand( sal_uInt16 nSub, sal_uInt32 nFormat, else break; - if (aDate.IsValid()) + if (aDate.IsValidAndGregorian()) { switch (nExtSub & ~DI_SUB_FIXED) { diff --git a/sw/source/ui/docvw/SidebarWin.cxx b/sw/source/ui/docvw/SidebarWin.cxx index fe2b53c..311e5bd 100644 --- a/sw/source/ui/docvw/SidebarWin.cxx +++ b/sw/source/ui/docvw/SidebarWin.cxx @@ -415,7 +415,7 @@ void SwSidebarWin::CheckMetaText() { sMeta = String(SW_RES(STR_POSTIT_YESTERDAY)); } - else if (aDate.IsValid() ) + else if (aDate.IsValidAndGregorian() ) { sMeta = rLocalData.getDate(aDate); } diff --git a/tools/inc/tools/date.hxx b/tools/inc/tools/date.hxx index 183f6af..a9d0e0d 100644 --- a/tools/inc/tools/date.hxx +++ b/tools/inc/tools/date.hxx @@ -80,7 +80,11 @@ public: sal_uInt16 GetDaysInMonth() const; sal_uInt16 GetDaysInYear() const { return (IsLeapYear()) ? 366 : 365; } sal_Bool IsLeapYear() const; - sal_Bool IsValid() const; + /** If the represented date is valid (1<=month<=12, 1<=day<=(28,29,30,31) + depending on month/year) AND is of the Gregorian calendar (1582-10-15 + <= date) (AND implicitly date <= 9999-12-31 due to internal + representation) */ + sal_Bool IsValidAndGregorian() const; sal_Bool IsBetween( const Date& rFrom, const Date& rTo ) const { return ((nDate >= rFrom.nDate) && diff --git a/tools/source/datetime/tdate.cxx b/tools/source/datetime/tdate.cxx index 47af8c0..06b0bc4 100644 --- a/tools/source/datetime/tdate.cxx +++ b/tools/source/datetime/tdate.cxx @@ -318,7 +318,7 @@ sal_Bool Date::IsLeapYear() const // ----------------------------------------------------------------------- -sal_Bool Date::IsValid() const +sal_Bool Date::IsValidAndGregorian() const { sal_uInt16 nDay = GetDay(); sal_uInt16 nMonth = GetMonth(); diff --git a/tools/source/inet/inetmsg.cxx b/tools/source/inet/inetmsg.cxx index 42ab896..e0db594 100644 --- a/tools/source/inet/inetmsg.cxx +++ b/tools/source/inet/inetmsg.cxx @@ -431,7 +431,7 @@ sal_Bool INetRFC822Message::ParseDateField ( return sal_False; } - return (rDateTime.IsValid() && + return (rDateTime.IsValidAndGregorian() && !((rDateTime.GetSec() > 59) || (rDateTime.GetMin() > 59) || (rDateTime.GetHour() > 23) )); diff --git a/vcl/source/control/field2.cxx b/vcl/source/control/field2.cxx index 31e9403..5fadf7e 100644 --- a/vcl/source/control/field2.cxx +++ b/vcl/source/control/field2.cxx @@ -1309,7 +1309,7 @@ static sal_Bool ImplDateGetValue( const XubString& rStr, Date& rDate, ExtDateFie Date aNewDate( nDay, nMonth, nYear ); DateFormatter::ExpandCentury( aNewDate, utl::MiscCfg().GetYear2000() ); - if ( aNewDate.IsValid() ) + if ( aNewDate.IsValidAndGregorian() ) { rDate = aNewDate; return sal_True; _______________________________________________ Libreoffice-commits mailing list Libreoffice-commits@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits