[Libreoffice-commits] .: 4 commits - chart2/source sax/qa sax/source sc/source sd/source sfx2/source svl/source svtools/source sw/source tools/inc tools/source vcl/source xmloff/source

Eike Rathke erack at kemper.freedesktop.org
Tue Nov 29 17:07:05 PST 2011


 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 <erack at 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 <erack at 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 <erack at 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 <erack at 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;


More information about the Libreoffice-commits mailing list