LCOV - code coverage report
Current view: top level - tools/source/datetime - tdate.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 165 251 65.7 %
Date: 2015-06-13 12:38:46 Functions: 26 30 86.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #if defined( WNT )
      21             : #include <windows.h>
      22             : #else
      23             : #include <time.h>
      24             : #endif
      25             : 
      26             : #include <tools/date.hxx>
      27             : #include <sal/log.hxx>
      28             : 
      29             : static const sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
      30             :                                              31, 31, 30, 31, 30, 31 };
      31             : 
      32             : #define MAX_DAYS    3636532
      33             : 
      34       50152 : inline bool ImpIsLeapYear( sal_uInt16 nYear )
      35             : {
      36       97995 :     return ( ( ((nYear % 4) == 0) && ((nYear % 100) != 0) ) ||
      37       97995 :              ( (nYear % 400) == 0 ) );
      38             : }
      39             : 
      40             : // All callers must have sanitized or normalized month and year values!
      41      359346 : inline sal_uInt16 ImplDaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
      42             : {
      43      359346 :     if ( nMonth != 2 )
      44      309202 :         return aDaysInMonth[nMonth-1];
      45             :     else
      46             :     {
      47       50144 :         if (ImpIsLeapYear(nYear))
      48        2321 :             return aDaysInMonth[nMonth-1] + 1;
      49             :         else
      50       47823 :             return aDaysInMonth[nMonth-1];
      51             :     }
      52             : }
      53             : 
      54             : // static
      55           4 : sal_uInt16 Date::GetDaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
      56             : {
      57             :     SAL_WARN_IF( nMonth < 1 || 12 < nMonth, "tools", "Date::GetDaysInMonth - nMonth out of bounds " << nMonth);
      58           4 :     if (nMonth < 1)
      59           0 :         nMonth = 1;
      60           4 :     else if (12 < nMonth)
      61           0 :         nMonth = 12;
      62           4 :     return ImplDaysInMonth( nMonth, nYear);
      63             : }
      64             : 
      65       54585 : long Date::GetAsNormalizedDays() const
      66             : {
      67             :     // This is a very common datum we often calculate from.
      68       54585 :     if (nDate == 18991230) // 1899-12-30
      69             :     {
      70             :         assert(DateToDays( GetDay(), GetMonth(), GetYear() ) == 693594);
      71       25218 :         return 693594;
      72             :     }
      73       29367 :     return DateToDays( GetDay(), GetMonth(), GetYear() );
      74             : }
      75             : 
      76       29400 : long Date::DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
      77             : {
      78             :     long nDays;
      79             : 
      80       29400 :     Normalize( nDay, nMonth, nYear);
      81             : 
      82       29400 :     nDays = ((sal_uIntPtr)nYear-1) * 365;
      83       29400 :     nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
      84      133613 :     for( sal_uInt16 i = 1; i < nMonth; i++ )
      85      104213 :         nDays += ImplDaysInMonth(i,nYear);
      86       29400 :     nDays += nDay;
      87       29400 :     return nDays;
      88             : }
      89             : 
      90       24035 : static void DaysToDate( long nDays,
      91             :                         sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
      92             : {
      93             :     long    nTempDays;
      94       24035 :     long    i = 0;
      95             :     bool    bCalc;
      96             : 
      97       26871 :     do
      98             :     {
      99       26871 :         nTempDays = (long)nDays;
     100       26871 :         rYear = (sal_uInt16)((nTempDays / 365) - i);
     101       26871 :         nTempDays -= ((sal_uIntPtr)rYear-1) * 365;
     102       26871 :         nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
     103       26871 :         bCalc = false;
     104       26871 :         if ( nTempDays < 1 )
     105             :         {
     106        2836 :             i++;
     107        2836 :             bCalc = true;
     108             :         }
     109             :         else
     110             :         {
     111       24035 :             if ( nTempDays > 365 )
     112             :             {
     113           8 :                 if ( (nTempDays != 366) || !ImpIsLeapYear( rYear ) )
     114             :                 {
     115           0 :                     i--;
     116           0 :                     bCalc = true;
     117             :                 }
     118             :             }
     119             :         }
     120             :     }
     121             :     while ( bCalc );
     122             : 
     123       24035 :     rMonth = 1;
     124      145019 :     while ( (sal_uIntPtr)nTempDays > ImplDaysInMonth( rMonth, rYear ) )
     125             :     {
     126       96949 :         nTempDays -= ImplDaysInMonth( rMonth, rYear );
     127       96949 :         rMonth++;
     128             :     }
     129       24035 :     rDay = (sal_uInt16)nTempDays;
     130       24035 : }
     131             : 
     132       25359 : Date::Date( DateInitSystem )
     133             : {
     134             : #if defined WNT
     135             :     SYSTEMTIME aDateTime;
     136             :     GetLocalTime( &aDateTime );
     137             : 
     138             :     // Combine to date
     139             :     nDate = ((sal_uIntPtr)aDateTime.wDay) +
     140             :             (((sal_uIntPtr)aDateTime.wMonth)*100) +
     141             :             (((sal_uIntPtr)aDateTime.wYear)*10000);
     142             : #else
     143             :     time_t     nTmpTime;
     144             :     struct tm aTime;
     145             : 
     146             :     // get current time
     147       25359 :     nTmpTime = time( 0 );
     148             : 
     149             :     // compute date
     150       25359 :     if ( localtime_r( &nTmpTime, &aTime ) )
     151             :     {
     152             :         nDate = ((sal_uIntPtr)aTime.tm_mday) +
     153       25359 :                 (((sal_uIntPtr)(aTime.tm_mon+1))*100) +
     154       50718 :                 (((sal_uIntPtr)(aTime.tm_year+1900))*10000);
     155             :     }
     156             :     else
     157           0 :         nDate = 1 + 100 + (((sal_uIntPtr)1900)*10000);
     158             : #endif
     159       25359 : }
     160             : 
     161           8 : Date::Date( const ::com::sun::star::util::DateTime& rDateTime )
     162             : {
     163           8 :   init( rDateTime.Day, rDateTime.Month, rDateTime.Year );
     164           8 : }
     165             : 
     166         134 : void Date::SetDay( sal_uInt16 nNewDay )
     167             : {
     168         134 :     sal_uIntPtr  nMonth  = GetMonth();
     169         134 :     sal_uIntPtr  nYear   = GetYear();
     170             : 
     171         134 :     nDate = ((sal_uIntPtr)(nNewDay%100)) + (nMonth*100) + (nYear*10000);
     172         134 : }
     173             : 
     174         136 : void Date::SetMonth( sal_uInt16 nNewMonth )
     175             : {
     176         136 :     sal_uIntPtr  nDay    = GetDay();
     177         136 :     sal_uIntPtr  nYear   = GetYear();
     178             : 
     179         136 :     nDate = nDay + (((sal_uIntPtr)(nNewMonth%100))*100) + (nYear*10000);
     180         136 : }
     181             : 
     182         289 : void Date::SetYear( sal_uInt16 nNewYear )
     183             : {
     184         289 :     sal_uIntPtr  nDay   = GetDay();
     185         289 :     sal_uIntPtr  nMonth = GetMonth();
     186             : 
     187         289 :     nDate = nDay + (nMonth*100) + (((sal_uIntPtr)(nNewYear%10000))*10000);
     188         289 : }
     189             : 
     190          78 : DayOfWeek Date::GetDayOfWeek() const
     191             : {
     192          78 :     return (DayOfWeek)((sal_uIntPtr)(GetAsNormalizedDays()-1) % 7);
     193             : }
     194             : 
     195         208 : sal_uInt16 Date::GetDayOfYear() const
     196             : {
     197         208 :     sal_uInt16 nDay   = GetDay();
     198         208 :     sal_uInt16 nMonth = GetMonth();
     199         208 :     sal_uInt16 nYear  = GetYear();
     200         208 :     Normalize( nDay, nMonth, nYear);
     201             : 
     202         836 :     for( sal_uInt16 i = 1; i < nMonth; i++ )
     203         628 :          nDay = nDay + ::ImplDaysInMonth( i, nYear );   // += yields a warning on MSVC, so don't use it
     204         208 :     return nDay;
     205             : }
     206             : 
     207           0 : sal_uInt16 Date::GetWeekOfYear( DayOfWeek eStartDay,
     208             :                                 sal_Int16 nMinimumNumberOfDaysInWeek ) const
     209             : {
     210             :     short nWeek;
     211           0 :     short n1WDay = (short)Date( 1, 1, GetYear() ).GetDayOfWeek();
     212           0 :     short nDayOfYear = (short)GetDayOfYear();
     213             : 
     214             :     // weekdays start at 0, thus decrement one
     215           0 :     nDayOfYear--;
     216             :     // account for StartDay
     217           0 :     n1WDay = (n1WDay+(7-(short)eStartDay)) % 7;
     218             : 
     219           0 :     if (nMinimumNumberOfDaysInWeek < 1 || 7 < nMinimumNumberOfDaysInWeek)
     220             :     {
     221             :         SAL_WARN( "tools.datetime", "Date::GetWeekOfYear: invalid nMinimumNumberOfDaysInWeek" );
     222           0 :         nMinimumNumberOfDaysInWeek = 4;
     223             :     }
     224             : 
     225           0 :     if ( nMinimumNumberOfDaysInWeek == 1 )
     226             :     {
     227           0 :         nWeek = ((n1WDay+nDayOfYear)/7) + 1;
     228             :         // Set to 53rd week only if we're not in the
     229             :         // first week of the new year
     230           0 :         if ( nWeek == 54 )
     231           0 :             nWeek = 1;
     232           0 :         else if ( nWeek == 53 )
     233             :         {
     234           0 :             short nDaysInYear = (short)GetDaysInYear();
     235           0 :             short nDaysNextYear = (short)Date( 1, 1, GetYear()+1 ).GetDayOfWeek();
     236           0 :             nDaysNextYear = (nDaysNextYear+(7-(short)eStartDay)) % 7;
     237           0 :             if ( nDayOfYear > (nDaysInYear-nDaysNextYear-1) )
     238           0 :                 nWeek = 1;
     239             :         }
     240             :     }
     241           0 :     else if ( nMinimumNumberOfDaysInWeek == 7 )
     242             :     {
     243           0 :         nWeek = ((n1WDay+nDayOfYear)/7);
     244             :         // First week of a year is equal to the last week of the previous year
     245           0 :         if ( nWeek == 0 )
     246             :         {
     247           0 :             Date aLastDatePrevYear( 31, 12, GetYear()-1 );
     248           0 :             nWeek = aLastDatePrevYear.GetWeekOfYear( eStartDay, nMinimumNumberOfDaysInWeek );
     249             :         }
     250             :     }
     251             :     else // ( nMinimumNumberOfDaysInWeek == somehing_else, commentary examples for 4 )
     252             :     {
     253             :         // x_monday - thursday
     254           0 :         if ( n1WDay < nMinimumNumberOfDaysInWeek )
     255           0 :             nWeek = 1;
     256             :         // Friday
     257           0 :         else if ( n1WDay == nMinimumNumberOfDaysInWeek )
     258           0 :             nWeek = 53;
     259             :         // Saturday
     260           0 :         else if ( n1WDay == nMinimumNumberOfDaysInWeek + 1 )
     261             :         {
     262             :             // Year after leapyear
     263           0 :             if ( Date( 1, 1, GetYear()-1 ).IsLeapYear() )
     264           0 :                 nWeek = 53;
     265             :             else
     266           0 :                 nWeek = 52;
     267             :         }
     268             :         // Sunday
     269             :         else
     270           0 :             nWeek = 52;
     271             : 
     272           0 :         if ( (nWeek == 1) || (nDayOfYear + n1WDay > 6) )
     273             :         {
     274           0 :             if ( nWeek == 1 )
     275           0 :                 nWeek += (nDayOfYear + n1WDay) / 7;
     276             :             else
     277           0 :                 nWeek = (nDayOfYear + n1WDay) / 7;
     278           0 :             if ( nWeek == 53 )
     279             :             {
     280             :                 // next x_Sunday == first x_Sunday in the new year
     281             :                 // == still the same week!
     282           0 :                 long nTempDays = GetAsNormalizedDays();
     283             : 
     284           0 :                 nTempDays +=  6 - (GetDayOfWeek()+(7-(short)eStartDay)) % 7;
     285             :                 sal_uInt16  nDay;
     286             :                 sal_uInt16  nMonth;
     287             :                 sal_uInt16  nYear;
     288           0 :                 DaysToDate( nTempDays, nDay, nMonth, nYear );
     289           0 :                 nWeek = Date( nDay, nMonth, nYear ).GetWeekOfYear( eStartDay, nMinimumNumberOfDaysInWeek );
     290             :             }
     291             :         }
     292             :     }
     293             : 
     294           0 :     return (sal_uInt16)nWeek;
     295             : }
     296             : 
     297        3119 : sal_uInt16 Date::GetDaysInMonth() const
     298             : {
     299        3119 :     sal_uInt16 nDay   = GetDay();
     300        3119 :     sal_uInt16 nMonth = GetMonth();
     301        3119 :     sal_uInt16 nYear  = GetYear();
     302        3119 :     Normalize( nDay, nMonth, nYear);
     303             : 
     304        3119 :     return ImplDaysInMonth( nMonth, nYear );
     305             : }
     306             : 
     307           0 : bool Date::IsLeapYear() const
     308             : {
     309           0 :     sal_uInt16 nYear = GetYear();
     310           0 :     return ImpIsLeapYear( nYear );
     311             : }
     312             : 
     313         468 : bool Date::IsValidAndGregorian() const
     314             : {
     315         468 :     sal_uInt16 nDay   = GetDay();
     316         468 :     sal_uInt16 nMonth = GetMonth();
     317         468 :     sal_uInt16 nYear  = GetYear();
     318             : 
     319         468 :     if ( !nMonth || (nMonth > 12) )
     320           7 :         return false;
     321         461 :     if ( !nDay || (nDay > ImplDaysInMonth( nMonth, nYear )) )
     322           0 :         return false;
     323         461 :     else if ( nYear <= 1582 )
     324             :     {
     325           0 :         if ( nYear < 1582 )
     326           0 :             return false;
     327           0 :         else if ( nMonth < 10 )
     328           0 :             return false;
     329           0 :         else if ( (nMonth == 10) && (nDay < 15) )
     330           0 :             return false;
     331             :     }
     332             : 
     333         461 :     return true;
     334             : }
     335             : 
     336         259 : bool Date::IsValidDate() const
     337             : {
     338         259 :     return IsValidDate( GetDay(), GetMonth(), GetYear());
     339             : }
     340             : 
     341             : //static
     342       32990 : bool Date::IsValidDate( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
     343             : {
     344       32990 :     if ( !nMonth || (nMonth > 12) )
     345          15 :         return false;
     346       32975 :     if ( !nDay || (nDay > ImplDaysInMonth( nMonth, nYear )) )
     347           0 :         return false;
     348       32975 :     return true;
     349             : }
     350             : 
     351           4 : bool Date::Normalize()
     352             : {
     353           4 :     sal_uInt16 nDay   = GetDay();
     354           4 :     sal_uInt16 nMonth = GetMonth();
     355           4 :     sal_uInt16 nYear  = GetYear();
     356             : 
     357           4 :     if (!Normalize( nDay, nMonth, nYear))
     358           4 :         return false;
     359             : 
     360           0 :     SetDay( nDay);
     361           0 :     SetMonth( nMonth);
     362           0 :     SetYear( nYear);
     363             : 
     364           0 :     return true;
     365             : }
     366             : 
     367             : //static
     368       32731 : bool Date::Normalize( sal_uInt16 & rDay, sal_uInt16 & rMonth, sal_uInt16 & rYear )
     369             : {
     370       32731 :     if (IsValidDate( rDay, rMonth, rYear))
     371       32718 :         return false;
     372             : 
     373          13 :     if (rMonth > 12)
     374             :     {
     375           0 :         rYear += rMonth / 12;
     376           0 :         rMonth = rMonth % 12;
     377             :     }
     378          13 :     if (!rMonth)
     379             :     {
     380          13 :         if (!rYear)
     381             :         {
     382          13 :             rYear = 0;
     383          13 :             rMonth = 1;
     384          13 :             if (rDay > 31)
     385          11 :                 rDay -= 31;
     386             :             else
     387           2 :                 rDay = 1;
     388             :         }
     389             :         else
     390             :         {
     391           0 :             --rYear;
     392           0 :             rMonth = 12;
     393             :         }
     394             :     }
     395             :     sal_uInt16 nDays;
     396          26 :     while (rDay > (nDays = ImplDaysInMonth( rMonth, rYear)))
     397             :     {
     398           0 :         rDay -= nDays;
     399           0 :         if (rMonth < 12)
     400           0 :             ++rMonth;
     401             :         else
     402             :         {
     403           0 :             ++rYear;
     404           0 :             rMonth = 1;
     405             :         }
     406             :     }
     407          13 :     if (rYear > 9999)
     408             :     {
     409           0 :         rDay = 31;
     410           0 :         rMonth = 12;
     411           0 :         rYear = 9999;
     412             :     }
     413          13 :     return true;
     414             : }
     415             : 
     416       23938 : Date& Date::operator +=( long nDays )
     417             : {
     418             :     sal_uInt16  nDay;
     419             :     sal_uInt16  nMonth;
     420             :     sal_uInt16  nYear;
     421             : 
     422       23938 :     if (nDays == 0)
     423          23 :         return *this;
     424             : 
     425       23915 :     long nTempDays = GetAsNormalizedDays();
     426             : 
     427       23915 :     nTempDays += nDays;
     428       23915 :     if ( nTempDays > MAX_DAYS )
     429           0 :         nDate = 31 + (12*100) + (((sal_uIntPtr)9999)*10000);
     430       23915 :     else if ( nTempDays <= 0 )
     431           0 :         nDate = 1 + 100;
     432             :     else
     433             :     {
     434       23915 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     435       23915 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     436             :     }
     437             : 
     438       23915 :     return *this;
     439             : }
     440             : 
     441          71 : Date& Date::operator -=( long nDays )
     442             : {
     443             :     sal_uInt16  nDay;
     444             :     sal_uInt16  nMonth;
     445             :     sal_uInt16  nYear;
     446             : 
     447          71 :     if (nDays == 0)
     448           0 :         return *this;
     449             : 
     450          71 :     long nTempDays = GetAsNormalizedDays();
     451             : 
     452          71 :     nTempDays -= nDays;
     453          71 :     if ( nTempDays > MAX_DAYS )
     454           0 :         nDate = 31 + (12*100) + (((sal_uIntPtr)9999)*10000);
     455          71 :     else if ( nTempDays <= 0 )
     456           0 :         nDate = 1 + 100;
     457             :     else
     458             :     {
     459          71 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     460          71 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     461             :     }
     462             : 
     463          71 :     return *this;
     464             : }
     465             : 
     466          37 : Date& Date::operator ++()
     467             : {
     468             :     sal_uInt16  nDay;
     469             :     sal_uInt16  nMonth;
     470             :     sal_uInt16  nYear;
     471          37 :     long nTempDays = GetAsNormalizedDays();
     472             : 
     473          37 :     if ( nTempDays < MAX_DAYS )
     474             :     {
     475          37 :         nTempDays++;
     476          37 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     477          37 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     478             :     }
     479             : 
     480          37 :     return *this;
     481             : }
     482             : 
     483          12 : Date& Date::operator --()
     484             : {
     485             :     sal_uInt16  nDay;
     486             :     sal_uInt16  nMonth;
     487             :     sal_uInt16  nYear;
     488          12 :     long nTempDays = GetAsNormalizedDays();
     489             : 
     490          12 :     if ( nTempDays > 1 )
     491             :     {
     492          12 :         nTempDays--;
     493          12 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     494          12 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     495             :     }
     496          12 :     return *this;
     497             : }
     498             : 
     499           0 : Date Date::operator ++( int )
     500             : {
     501           0 :     Date aOldDate = *this;
     502           0 :     Date::operator++();
     503           0 :     return aOldDate;
     504             : }
     505             : 
     506           0 : Date Date::operator --( int )
     507             : {
     508           0 :     Date aOldDate = *this;
     509           0 :     Date::operator--();
     510           0 :     return aOldDate;
     511             : }
     512             : 
     513       12376 : Date operator +( const Date& rDate, long nDays )
     514             : {
     515       12376 :     Date aDate( rDate );
     516       12376 :     aDate += nDays;
     517       12376 :     return aDate;
     518             : }
     519             : 
     520          71 : Date operator -( const Date& rDate, long nDays )
     521             : {
     522          71 :     Date aDate( rDate );
     523          71 :     aDate -= nDays;
     524          71 :     return aDate;
     525             : }
     526             : 
     527       15236 : long operator -( const Date& rDate1, const Date& rDate2 )
     528             : {
     529       15236 :     sal_uIntPtr nTempDays1 = rDate1.GetAsNormalizedDays();
     530       15236 :     sal_uIntPtr nTempDays2 = rDate2.GetAsNormalizedDays();
     531             : 
     532       15236 :     return nTempDays1 - nTempDays2;
     533             : }
     534             : 
     535             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11