LCOV - code coverage report
Current view: top level - libreoffice/tools/source/datetime - tdate.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 112 234 47.9 %
Date: 2012-12-27 Functions: 18 27 66.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             : #ifdef  MACOSX
      30             : extern "C" {
      31             : struct tm *localtime_r(const time_t *timep, struct tm *buffer);
      32             : }
      33             : #endif
      34             : 
      35             : static sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
      36             :                                        31, 31, 30, 31, 30, 31 };
      37             : 
      38             : #define MAX_DAYS    3636532
      39             : 
      40        3618 : inline sal_Bool ImpIsLeapYear( sal_uInt16 nYear )
      41             : {
      42             :     return ( ( ((nYear % 4) == 0) && ((nYear % 100) != 0) ) ||
      43        3618 :              ( (nYear % 400) == 0 ) );
      44             : }
      45             : 
      46             : // All callers must have sanitized or normalized month and year values!
      47       43767 : inline sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
      48             : {
      49       43767 :     if ( nMonth != 2 )
      50       40149 :         return aDaysInMonth[nMonth-1];
      51             :     else
      52             :     {
      53        3618 :         if (ImpIsLeapYear(nYear))
      54        1584 :             return aDaysInMonth[nMonth-1] + 1;
      55             :         else
      56        2034 :             return aDaysInMonth[nMonth-1];
      57             :     }
      58             : }
      59             : 
      60        3716 : long Date::DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
      61             : {
      62             :     long nDays;
      63             : 
      64        3716 :     Normalize( nDay, nMonth, nYear);
      65             : 
      66        3716 :     nDays = ((sal_uIntPtr)nYear-1) * 365;
      67        3716 :     nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
      68       36457 :     for( sal_uInt16 i = 1; i < nMonth; i++ )
      69       32741 :         nDays += DaysInMonth(i,nYear);
      70        3716 :     nDays += nDay;
      71        3716 :     return nDays;
      72             : }
      73             : 
      74        1944 : static void DaysToDate( long nDays,
      75             :                         sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
      76             : {
      77             :     long    nTempDays;
      78        1944 :     long    i = 0;
      79             :     sal_Bool    bCalc;
      80             : 
      81        2102 :     do
      82             :     {
      83        2102 :         nTempDays = (long)nDays;
      84        2102 :         rYear = (sal_uInt16)((nTempDays / 365) - i);
      85        2102 :         nTempDays -= ((sal_uIntPtr)rYear-1) * 365;
      86        2102 :         nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
      87        2102 :         bCalc = sal_False;
      88        2102 :         if ( nTempDays < 1 )
      89             :         {
      90         158 :             i++;
      91         158 :             bCalc = sal_True;
      92             :         }
      93             :         else
      94             :         {
      95        1944 :             if ( nTempDays > 365 )
      96             :             {
      97           0 :                 if ( (nTempDays != 366) || !ImpIsLeapYear( rYear ) )
      98             :                 {
      99           0 :                     i--;
     100           0 :                     bCalc = sal_True;
     101             :                 }
     102             :             }
     103             :         }
     104             :     }
     105             :     while ( bCalc );
     106             : 
     107        1944 :     rMonth = 1;
     108        5804 :     while ( (sal_uIntPtr)nTempDays > DaysInMonth( rMonth, rYear ) )
     109             :     {
     110        1916 :         nTempDays -= DaysInMonth( rMonth, rYear );
     111        1916 :         rMonth++;
     112             :     }
     113        1944 :     rDay = (sal_uInt16)nTempDays;
     114        1944 : }
     115             : 
     116        2451 : Date::Date( DateInitSystem )
     117             : {
     118             : #if defined WNT
     119             :     SYSTEMTIME aDateTime;
     120             :     GetLocalTime( &aDateTime );
     121             : 
     122             :     // Combine to date
     123             :     nDate = ((sal_uIntPtr)aDateTime.wDay) +
     124             :             (((sal_uIntPtr)aDateTime.wMonth)*100) +
     125             :             (((sal_uIntPtr)aDateTime.wYear)*10000);
     126             : #else
     127             :     time_t     nTmpTime;
     128             :     struct tm aTime;
     129             : 
     130             :     // get current time
     131        2451 :     nTmpTime = time( 0 );
     132             : 
     133             :     // compute date
     134        2451 :     if ( localtime_r( &nTmpTime, &aTime ) )
     135             :     {
     136             :         nDate = ((sal_uIntPtr)aTime.tm_mday) +
     137             :                 (((sal_uIntPtr)(aTime.tm_mon+1))*100) +
     138        2451 :                 (((sal_uIntPtr)(aTime.tm_year+1900))*10000);
     139             :     }
     140             :     else
     141           0 :         nDate = 1 + 100 + (((sal_uIntPtr)1900)*10000);
     142             : #endif
     143        2451 : }
     144             : 
     145           8 : void Date::SetDay( sal_uInt16 nNewDay )
     146             : {
     147           8 :     sal_uIntPtr  nMonth  = GetMonth();
     148           8 :     sal_uIntPtr  nYear   = GetYear();
     149             : 
     150           8 :     nDate = ((sal_uIntPtr)(nNewDay%100)) + (nMonth*100) + (nYear*10000);
     151           8 : }
     152             : 
     153           8 : void Date::SetMonth( sal_uInt16 nNewMonth )
     154             : {
     155           8 :     sal_uIntPtr  nDay    = GetDay();
     156           8 :     sal_uIntPtr  nYear   = GetYear();
     157             : 
     158           8 :     nDate = nDay + (((sal_uIntPtr)(nNewMonth%100))*100) + (nYear*10000);
     159           8 : }
     160             : 
     161          16 : void Date::SetYear( sal_uInt16 nNewYear )
     162             : {
     163          16 :     sal_uIntPtr  nDay   = GetDay();
     164          16 :     sal_uIntPtr  nMonth = GetMonth();
     165             : 
     166          16 :     nDate = nDay + (nMonth*100) + (((sal_uIntPtr)(nNewYear%10000))*10000);
     167          16 : }
     168             : 
     169           0 : DayOfWeek Date::GetDayOfWeek() const
     170             : {
     171           0 :     return (DayOfWeek)((sal_uIntPtr)(DateToDays( GetDay(), GetMonth(), GetYear() )-1) % 7);
     172             : }
     173             : 
     174           0 : sal_uInt16 Date::GetDayOfYear() const
     175             : {
     176           0 :     sal_uInt16 nDay   = GetDay();
     177           0 :     sal_uInt16 nMonth = GetMonth();
     178           0 :     sal_uInt16 nYear  = GetYear();
     179           0 :     Normalize( nDay, nMonth, nYear);
     180             : 
     181           0 :     for( sal_uInt16 i = 1; i < nMonth; i++ )
     182           0 :          nDay = nDay + ::DaysInMonth( i, nYear );   // += yields a warning on MSVC, so don't use it
     183           0 :     return nDay;
     184             : }
     185             : 
     186           0 : sal_uInt16 Date::GetWeekOfYear( DayOfWeek eStartDay,
     187             :                             sal_Int16 nMinimumNumberOfDaysInWeek ) const
     188             : {
     189             :     short nWeek;
     190           0 :     short n1WDay = (short)Date( 1, 1, GetYear() ).GetDayOfWeek();
     191           0 :     short nDayOfYear = (short)GetDayOfYear();
     192             : 
     193             :     // weekdays start at 0, thus decrement one
     194           0 :     nDayOfYear--;
     195             :     // account for StartDay
     196           0 :     n1WDay = (n1WDay+(7-(short)eStartDay)) % 7;
     197             : 
     198           0 :     if (nMinimumNumberOfDaysInWeek < 1 || 7 < nMinimumNumberOfDaysInWeek)
     199             :     {
     200             :         SAL_WARN( "tools", "Date::GetWeekOfYear: invalid nMinimumNumberOfDaysInWeek" );
     201           0 :         nMinimumNumberOfDaysInWeek = 4;
     202             :     }
     203             : 
     204           0 :     if ( nMinimumNumberOfDaysInWeek == 1 )
     205             :     {
     206           0 :         nWeek = ((n1WDay+nDayOfYear)/7) + 1;
     207             :         // Set to 53rd week only if we're not in the
     208             :         // first week of the new year
     209           0 :         if ( nWeek == 54 )
     210           0 :             nWeek = 1;
     211           0 :         else if ( nWeek == 53 )
     212             :         {
     213           0 :             short nDaysInYear = (short)GetDaysInYear();
     214           0 :             short nDaysNextYear = (short)Date( 1, 1, GetYear()+1 ).GetDayOfWeek();
     215           0 :             nDaysNextYear = (nDaysNextYear+(7-(short)eStartDay)) % 7;
     216           0 :             if ( nDayOfYear > (nDaysInYear-nDaysNextYear-1) )
     217           0 :                 nWeek = 1;
     218             :         }
     219             :     }
     220           0 :     else if ( nMinimumNumberOfDaysInWeek == 7 )
     221             :     {
     222           0 :         nWeek = ((n1WDay+nDayOfYear)/7);
     223             :         // First week of a year is equal to the last week of the previous year
     224           0 :         if ( nWeek == 0 )
     225             :         {
     226           0 :             Date aLastDatePrevYear( 31, 12, GetYear()-1 );
     227           0 :             nWeek = aLastDatePrevYear.GetWeekOfYear( eStartDay, nMinimumNumberOfDaysInWeek );
     228             :         }
     229             :     }
     230             :     else // ( nMinimumNumberOfDaysInWeek == somehing_else, commentary examples for 4 )
     231             :     {
     232             :         // x_monday - thursday
     233           0 :         if ( n1WDay < nMinimumNumberOfDaysInWeek )
     234           0 :             nWeek = 1;
     235             :         // Friday
     236           0 :         else if ( n1WDay == nMinimumNumberOfDaysInWeek )
     237           0 :             nWeek = 53;
     238             :         // Saturday
     239           0 :         else if ( n1WDay == nMinimumNumberOfDaysInWeek + 1 )
     240             :         {
     241             :             // Year after leapyear
     242           0 :             if ( Date( 1, 1, GetYear()-1 ).IsLeapYear() )
     243           0 :                 nWeek = 53;
     244             :             else
     245           0 :                 nWeek = 52;
     246             :         }
     247             :         // Sunday
     248             :         else
     249           0 :             nWeek = 52;
     250             : 
     251           0 :         if ( (nWeek == 1) || (nDayOfYear + n1WDay > 6) )
     252             :         {
     253           0 :             if ( nWeek == 1 )
     254           0 :                 nWeek += (nDayOfYear + n1WDay) / 7;
     255             :             else
     256           0 :                 nWeek = (nDayOfYear + n1WDay) / 7;
     257           0 :             if ( nWeek == 53 )
     258             :             {
     259             :                 // next x_Sunday == first x_Sunday in the new year
     260             :                 // == still the same week!
     261           0 :                 long nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
     262           0 :                 nTempDays +=  6 - (GetDayOfWeek()+(7-(short)eStartDay)) % 7;
     263             :                 sal_uInt16  nDay;
     264             :                 sal_uInt16  nMonth;
     265             :                 sal_uInt16  nYear;
     266           0 :                 DaysToDate( nTempDays, nDay, nMonth, nYear );
     267           0 :                 nWeek = Date( nDay, nMonth, nYear ).GetWeekOfYear( eStartDay, nMinimumNumberOfDaysInWeek );
     268             :             }
     269             :         }
     270             :     }
     271             : 
     272           0 :     return (sal_uInt16)nWeek;
     273             : }
     274             : 
     275         761 : sal_uInt16 Date::GetDaysInMonth() const
     276             : {
     277         761 :     sal_uInt16 nDay   = GetDay();
     278         761 :     sal_uInt16 nMonth = GetMonth();
     279         761 :     sal_uInt16 nYear  = GetYear();
     280         761 :     Normalize( nDay, nMonth, nYear);
     281             : 
     282         761 :     return DaysInMonth( nMonth, nYear );
     283             : }
     284             : 
     285           0 : sal_Bool Date::IsLeapYear() const
     286             : {
     287           0 :     sal_uInt16 nYear = GetYear();
     288           0 :     return ImpIsLeapYear( nYear );
     289             : }
     290             : 
     291           6 : sal_Bool Date::IsValidAndGregorian() const
     292             : {
     293           6 :     sal_uInt16 nDay   = GetDay();
     294           6 :     sal_uInt16 nMonth = GetMonth();
     295           6 :     sal_uInt16 nYear  = GetYear();
     296             : 
     297           6 :     if ( !nMonth || (nMonth > 12) )
     298           2 :         return sal_False;
     299           4 :     if ( !nDay || (nDay > DaysInMonth( nMonth, nYear )) )
     300           0 :         return sal_False;
     301           4 :     else if ( nYear <= 1582 )
     302             :     {
     303           0 :         if ( nYear < 1582 )
     304           0 :             return sal_False;
     305           0 :         else if ( nMonth < 10 )
     306           0 :             return sal_False;
     307           0 :         else if ( (nMonth == 10) && (nDay < 15) )
     308           0 :             return sal_False;
     309             :     }
     310             : 
     311           4 :     return sal_True;
     312             : }
     313             : 
     314           0 : bool Date::IsValidDate() const
     315             : {
     316           0 :     return IsValidDate( GetDay(), GetMonth(), GetYear());
     317             : }
     318             : 
     319             : //static
     320        4485 : bool Date::IsValidDate( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
     321             : {
     322        4485 :     if ( !nMonth || (nMonth > 12) )
     323           0 :         return false;
     324        4485 :     if ( !nDay || (nDay > DaysInMonth( nMonth, nYear )) )
     325           0 :         return false;
     326        4485 :     return true;
     327             : }
     328             : 
     329           8 : bool Date::Normalize()
     330             : {
     331           8 :     sal_uInt16 nDay   = GetDay();
     332           8 :     sal_uInt16 nMonth = GetMonth();
     333           8 :     sal_uInt16 nYear  = GetYear();
     334             : 
     335           8 :     if (!Normalize( nDay, nMonth, nYear))
     336           8 :         return false;
     337             : 
     338           0 :     SetDay( nDay);
     339           0 :     SetMonth( nMonth);
     340           0 :     SetYear( nYear);
     341             : 
     342           0 :     return true;
     343             : }
     344             : 
     345             : //static
     346        4485 : bool Date::Normalize( sal_uInt16 & rDay, sal_uInt16 & rMonth, sal_uInt16 & rYear )
     347             : {
     348        4485 :     if (IsValidDate( rDay, rMonth, rYear))
     349        4485 :         return false;
     350             : 
     351           0 :     if (rMonth > 12)
     352             :     {
     353           0 :         rYear += rMonth / 12;
     354           0 :         rMonth = rMonth % 12;
     355             :     }
     356           0 :     if (!rMonth)
     357             :     {
     358           0 :         if (!rYear)
     359             :         {
     360           0 :             rYear = 0;
     361           0 :             rMonth = 1;
     362           0 :             if (rDay > 31)
     363           0 :                 rDay -= 31;
     364             :             else
     365           0 :                 rDay = 1;
     366             :         }
     367             :         else
     368             :         {
     369           0 :             --rYear;
     370           0 :             rMonth = 12;
     371             :         }
     372             :     }
     373             :     sal_uInt16 nDays;
     374           0 :     while (rDay > (nDays = DaysInMonth( rMonth, rYear)))
     375             :     {
     376           0 :         rDay -= nDays;
     377           0 :         if (rMonth < 12)
     378           0 :             ++rMonth;
     379             :         else
     380             :         {
     381           0 :             ++rYear;
     382           0 :             rMonth = 1;
     383             :         }
     384             :     }
     385           0 :     if (rYear > 9999)
     386             :     {
     387           0 :         rDay = 31;
     388           0 :         rMonth = 12;
     389           0 :         rYear = 9999;
     390             :     }
     391           0 :     return true;
     392             : }
     393             : 
     394        1938 : Date& Date::operator +=( long nDays )
     395             : {
     396             :     sal_uInt16  nDay;
     397             :     sal_uInt16  nMonth;
     398             :     sal_uInt16  nYear;
     399        1938 :     long    nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
     400             : 
     401        1938 :     nTempDays += nDays;
     402        1938 :     if ( nTempDays > MAX_DAYS )
     403           0 :         nDate = 31 + (12*100) + (((sal_uIntPtr)9999)*10000);
     404        1938 :     else if ( nTempDays <= 0 )
     405           0 :         nDate = 1 + 100;
     406             :     else
     407             :     {
     408        1938 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     409        1938 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     410             :     }
     411             : 
     412        1938 :     return *this;
     413             : }
     414             : 
     415           6 : Date& Date::operator -=( long nDays )
     416             : {
     417             :     sal_uInt16  nDay;
     418             :     sal_uInt16  nMonth;
     419             :     sal_uInt16  nYear;
     420           6 :     long    nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
     421             : 
     422           6 :     nTempDays -= nDays;
     423           6 :     if ( nTempDays > MAX_DAYS )
     424           0 :         nDate = 31 + (12*100) + (((sal_uIntPtr)9999)*10000);
     425           6 :     else if ( nTempDays <= 0 )
     426           0 :         nDate = 1 + 100;
     427             :     else
     428             :     {
     429           6 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     430           6 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     431             :     }
     432             : 
     433           6 :     return *this;
     434             : }
     435             : 
     436           0 : Date& Date::operator ++()
     437             : {
     438             :     sal_uInt16  nDay;
     439             :     sal_uInt16  nMonth;
     440             :     sal_uInt16  nYear;
     441           0 :     long    nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
     442             : 
     443           0 :     if ( nTempDays < MAX_DAYS )
     444             :     {
     445           0 :         nTempDays++;
     446           0 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     447           0 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     448             :     }
     449             : 
     450           0 :     return *this;
     451             : }
     452             : 
     453           0 : Date& Date::operator --()
     454             : {
     455             :     sal_uInt16  nDay;
     456             :     sal_uInt16  nMonth;
     457             :     sal_uInt16  nYear;
     458           0 :     long    nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
     459             : 
     460           0 :     if ( nTempDays > 1 )
     461             :     {
     462           0 :         nTempDays--;
     463           0 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     464           0 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     465             :     }
     466           0 :     return *this;
     467             : }
     468             : 
     469           0 : Date Date::operator ++( int )
     470             : {
     471           0 :     Date aOldDate = *this;
     472           0 :     Date::operator++();
     473           0 :     return aOldDate;
     474             : }
     475             : 
     476           0 : Date Date::operator --( int )
     477             : {
     478           0 :     Date aOldDate = *this;
     479           0 :     Date::operator--();
     480           0 :     return aOldDate;
     481             : }
     482             : 
     483        1296 : Date operator +( const Date& rDate, long nDays )
     484             : {
     485        1296 :     Date aDate( rDate );
     486        1296 :     aDate += nDays;
     487        1296 :     return aDate;
     488             : }
     489             : 
     490           6 : Date operator -( const Date& rDate, long nDays )
     491             : {
     492           6 :     Date aDate( rDate );
     493           6 :     aDate -= nDays;
     494           6 :     return aDate;
     495             : }
     496             : 
     497         886 : long operator -( const Date& rDate1, const Date& rDate2 )
     498             : {
     499        1772 :     sal_uIntPtr  nTempDays1 = Date::DateToDays( rDate1.GetDay(), rDate1.GetMonth(),
     500        2658 :                                     rDate1.GetYear() );
     501        1772 :     sal_uIntPtr  nTempDays2 = Date::DateToDays( rDate2.GetDay(), rDate2.GetMonth(),
     502        2658 :                                     rDate2.GetYear() );
     503         886 :     return nTempDays1 - nTempDays2;
     504             : }
     505             : 
     506             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10