diff options
author | Eike Rathke <erack@redhat.com> | 2011-11-30 02:05:23 +0100 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2011-11-30 02:05:23 +0100 |
commit | 6619955e72c1c2f29a32e82478d19147c0d7610a (patch) | |
tree | cc4e45e240718901d7be246f51c8e4e6dda1892b /tools | |
parent | dca69d5bb2d0e542de26624dd9f71fb87e1533f2 (diff) |
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()
Diffstat (limited to 'tools')
-rw-r--r-- | tools/source/datetime/tdate.cxx | 109 |
1 files changed, 105 insertions, 4 deletions
diff --git a/tools/source/datetime/tdate.cxx b/tools/source/datetime/tdate.cxx index 06b0bc4d1346..5deef5250b24 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; |