LCOV - code coverage report
Current view: top level - tools/source/datetime - tdate.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 177 248 71.4 %
Date: 2014-11-03 Functions: 26 29 89.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       52956 : inline bool ImpIsLeapYear( sal_uInt16 nYear )
      35             : {
      36      101414 :     return ( ( ((nYear % 4) == 0) && ((nYear % 100) != 0) ) ||
      37      101414 :              ( (nYear % 400) == 0 ) );
      38             : }
      39             : 
      40             : // All callers must have sanitized or normalized month and year values!
      41      557350 : inline sal_uInt16 ImplDaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
      42             : {
      43      557350 :     if ( nMonth != 2 )
      44      504402 :         return aDaysInMonth[nMonth-1];
      45             :     else
      46             :     {
      47       52948 :         if (ImpIsLeapYear(nYear))
      48        4536 :             return aDaysInMonth[nMonth-1] + 1;
      49             :         else
      50       48412 :             return aDaysInMonth[nMonth-1];
      51             :     }
      52             : }
      53             : 
      54             : // static
      55           8 : 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           8 :     if (nMonth < 1)
      59           0 :         nMonth = 1;
      60           8 :     else if (12 < nMonth)
      61           0 :         nMonth = 12;
      62           8 :     return ImplDaysInMonth( nMonth, nYear);
      63             : }
      64             : 
      65       42434 : long Date::GetAsNormalizedDays() const
      66             : {
      67             :     // This is a very common datum we often calculate from.
      68       42434 :     if (nDate == 18991230) // 1899-12-30
      69             :     {
      70             :         assert(DateToDays( GetDay(), GetMonth(), GetYear() ) == 693594);
      71       15824 :         return 693594;
      72             :     }
      73       26610 :     return DateToDays( GetDay(), GetMonth(), GetYear() );
      74             : }
      75             : 
      76       26676 : long Date::DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
      77             : {
      78             :     long nDays;
      79             : 
      80       26676 :     Normalize( nDay, nMonth, nYear);
      81             : 
      82       26676 :     nDays = ((sal_uIntPtr)nYear-1) * 365;
      83       26676 :     nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
      84      198640 :     for( sal_uInt16 i = 1; i < nMonth; i++ )
      85      171964 :         nDays += ImplDaysInMonth(i,nYear);
      86       26676 :     nDays += nDay;
      87       26676 :     return nDays;
      88             : }
      89             : 
      90       20922 : static void DaysToDate( long nDays,
      91             :                         sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
      92             : {
      93             :     long    nTempDays;
      94       20922 :     long    i = 0;
      95             :     bool    bCalc;
      96             : 
      97       36418 :     do
      98             :     {
      99       36418 :         nTempDays = (long)nDays;
     100       36418 :         rYear = (sal_uInt16)((nTempDays / 365) - i);
     101       36418 :         nTempDays -= ((sal_uIntPtr)rYear-1) * 365;
     102       36418 :         nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
     103       36418 :         bCalc = false;
     104       36418 :         if ( nTempDays < 1 )
     105             :         {
     106       15496 :             i++;
     107       15496 :             bCalc = true;
     108             :         }
     109             :         else
     110             :         {
     111       20922 :             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       20922 :     rMonth = 1;
     124      205344 :     while ( (sal_uIntPtr)nTempDays > ImplDaysInMonth( rMonth, rYear ) )
     125             :     {
     126      163500 :         nTempDays -= ImplDaysInMonth( rMonth, rYear );
     127      163500 :         rMonth++;
     128             :     }
     129       20922 :     rDay = (sal_uInt16)nTempDays;
     130       20922 : }
     131             : 
     132       32977 : 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       32977 :     nTmpTime = time( 0 );
     148             : 
     149             :     // compute date
     150       32977 :     if ( localtime_r( &nTmpTime, &aTime ) )
     151             :     {
     152             :         nDate = ((sal_uIntPtr)aTime.tm_mday) +
     153       32977 :                 (((sal_uIntPtr)(aTime.tm_mon+1))*100) +
     154       65954 :                 (((sal_uIntPtr)(aTime.tm_year+1900))*10000);
     155             :     }
     156             :     else
     157           0 :         nDate = 1 + 100 + (((sal_uIntPtr)1900)*10000);
     158             : #endif
     159       32977 : }
     160             : 
     161         144 : void Date::SetDay( sal_uInt16 nNewDay )
     162             : {
     163         144 :     sal_uIntPtr  nMonth  = GetMonth();
     164         144 :     sal_uIntPtr  nYear   = GetYear();
     165             : 
     166         144 :     nDate = ((sal_uIntPtr)(nNewDay%100)) + (nMonth*100) + (nYear*10000);
     167         144 : }
     168             : 
     169         150 : void Date::SetMonth( sal_uInt16 nNewMonth )
     170             : {
     171         150 :     sal_uIntPtr  nDay    = GetDay();
     172         150 :     sal_uIntPtr  nYear   = GetYear();
     173             : 
     174         150 :     nDate = nDay + (((sal_uIntPtr)(nNewMonth%100))*100) + (nYear*10000);
     175         150 : }
     176             : 
     177         450 : void Date::SetYear( sal_uInt16 nNewYear )
     178             : {
     179         450 :     sal_uIntPtr  nDay   = GetDay();
     180         450 :     sal_uIntPtr  nMonth = GetMonth();
     181             : 
     182         450 :     nDate = nDay + (nMonth*100) + (((sal_uIntPtr)(nNewYear%10000))*10000);
     183         450 : }
     184             : 
     185          92 : DayOfWeek Date::GetDayOfWeek() const
     186             : {
     187          92 :     return (DayOfWeek)((sal_uIntPtr)(GetAsNormalizedDays()-1) % 7);
     188             : }
     189             : 
     190         244 : sal_uInt16 Date::GetDayOfYear() const
     191             : {
     192         244 :     sal_uInt16 nDay   = GetDay();
     193         244 :     sal_uInt16 nMonth = GetMonth();
     194         244 :     sal_uInt16 nYear  = GetYear();
     195         244 :     Normalize( nDay, nMonth, nYear);
     196             : 
     197         798 :     for( sal_uInt16 i = 1; i < nMonth; i++ )
     198         554 :          nDay = nDay + ::ImplDaysInMonth( i, nYear );   // += yields a warning on MSVC, so don't use it
     199         244 :     return nDay;
     200             : }
     201             : 
     202           4 : sal_uInt16 Date::GetWeekOfYear( DayOfWeek eStartDay,
     203             :                                 sal_Int16 nMinimumNumberOfDaysInWeek ) const
     204             : {
     205             :     short nWeek;
     206           4 :     short n1WDay = (short)Date( 1, 1, GetYear() ).GetDayOfWeek();
     207           4 :     short nDayOfYear = (short)GetDayOfYear();
     208             : 
     209             :     // weekdays start at 0, thus decrement one
     210           4 :     nDayOfYear--;
     211             :     // account for StartDay
     212           4 :     n1WDay = (n1WDay+(7-(short)eStartDay)) % 7;
     213             : 
     214           4 :     if (nMinimumNumberOfDaysInWeek < 1 || 7 < nMinimumNumberOfDaysInWeek)
     215             :     {
     216             :         SAL_WARN( "tools.datetime", "Date::GetWeekOfYear: invalid nMinimumNumberOfDaysInWeek" );
     217           0 :         nMinimumNumberOfDaysInWeek = 4;
     218             :     }
     219             : 
     220           4 :     if ( nMinimumNumberOfDaysInWeek == 1 )
     221             :     {
     222           0 :         nWeek = ((n1WDay+nDayOfYear)/7) + 1;
     223             :         // Set to 53rd week only if we're not in the
     224             :         // first week of the new year
     225           0 :         if ( nWeek == 54 )
     226           0 :             nWeek = 1;
     227           0 :         else if ( nWeek == 53 )
     228             :         {
     229           0 :             short nDaysInYear = (short)GetDaysInYear();
     230           0 :             short nDaysNextYear = (short)Date( 1, 1, GetYear()+1 ).GetDayOfWeek();
     231           0 :             nDaysNextYear = (nDaysNextYear+(7-(short)eStartDay)) % 7;
     232           0 :             if ( nDayOfYear > (nDaysInYear-nDaysNextYear-1) )
     233           0 :                 nWeek = 1;
     234             :         }
     235             :     }
     236           4 :     else if ( nMinimumNumberOfDaysInWeek == 7 )
     237             :     {
     238           0 :         nWeek = ((n1WDay+nDayOfYear)/7);
     239             :         // First week of a year is equal to the last week of the previous year
     240           0 :         if ( nWeek == 0 )
     241             :         {
     242           0 :             Date aLastDatePrevYear( 31, 12, GetYear()-1 );
     243           0 :             nWeek = aLastDatePrevYear.GetWeekOfYear( eStartDay, nMinimumNumberOfDaysInWeek );
     244             :         }
     245             :     }
     246             :     else // ( nMinimumNumberOfDaysInWeek == somehing_else, commentary examples for 4 )
     247             :     {
     248             :         // x_monday - thursday
     249           4 :         if ( n1WDay < nMinimumNumberOfDaysInWeek )
     250           2 :             nWeek = 1;
     251             :         // Friday
     252           2 :         else if ( n1WDay == nMinimumNumberOfDaysInWeek )
     253           0 :             nWeek = 53;
     254             :         // Saturday
     255           2 :         else if ( n1WDay == nMinimumNumberOfDaysInWeek + 1 )
     256             :         {
     257             :             // Year after leapyear
     258           0 :             if ( Date( 1, 1, GetYear()-1 ).IsLeapYear() )
     259           0 :                 nWeek = 53;
     260             :             else
     261           0 :                 nWeek = 52;
     262             :         }
     263             :         // Sunday
     264             :         else
     265           2 :             nWeek = 52;
     266             : 
     267           4 :         if ( (nWeek == 1) || (nDayOfYear + n1WDay > 6) )
     268             :         {
     269           2 :             if ( nWeek == 1 )
     270           2 :                 nWeek += (nDayOfYear + n1WDay) / 7;
     271             :             else
     272           0 :                 nWeek = (nDayOfYear + n1WDay) / 7;
     273           2 :             if ( nWeek == 53 )
     274             :             {
     275             :                 // next x_Sunday == first x_Sunday in the new year
     276             :                 // == still the same week!
     277           0 :                 long nTempDays = GetAsNormalizedDays();
     278             : 
     279           0 :                 nTempDays +=  6 - (GetDayOfWeek()+(7-(short)eStartDay)) % 7;
     280             :                 sal_uInt16  nDay;
     281             :                 sal_uInt16  nMonth;
     282             :                 sal_uInt16  nYear;
     283           0 :                 DaysToDate( nTempDays, nDay, nMonth, nYear );
     284           0 :                 nWeek = Date( nDay, nMonth, nYear ).GetWeekOfYear( eStartDay, nMinimumNumberOfDaysInWeek );
     285             :             }
     286             :         }
     287             :     }
     288             : 
     289           4 :     return (sal_uInt16)nWeek;
     290             : }
     291             : 
     292        4486 : sal_uInt16 Date::GetDaysInMonth() const
     293             : {
     294        4486 :     sal_uInt16 nDay   = GetDay();
     295        4486 :     sal_uInt16 nMonth = GetMonth();
     296        4486 :     sal_uInt16 nYear  = GetYear();
     297        4486 :     Normalize( nDay, nMonth, nYear);
     298             : 
     299        4486 :     return ImplDaysInMonth( nMonth, nYear );
     300             : }
     301             : 
     302           0 : bool Date::IsLeapYear() const
     303             : {
     304           0 :     sal_uInt16 nYear = GetYear();
     305           0 :     return ImpIsLeapYear( nYear );
     306             : }
     307             : 
     308         542 : bool Date::IsValidAndGregorian() const
     309             : {
     310         542 :     sal_uInt16 nDay   = GetDay();
     311         542 :     sal_uInt16 nMonth = GetMonth();
     312         542 :     sal_uInt16 nYear  = GetYear();
     313             : 
     314         542 :     if ( !nMonth || (nMonth > 12) )
     315          14 :         return false;
     316         528 :     if ( !nDay || (nDay > ImplDaysInMonth( nMonth, nYear )) )
     317           0 :         return false;
     318         528 :     else if ( nYear <= 1582 )
     319             :     {
     320           0 :         if ( nYear < 1582 )
     321           0 :             return false;
     322           0 :         else if ( nMonth < 10 )
     323           0 :             return false;
     324           0 :         else if ( (nMonth == 10) && (nDay < 15) )
     325           0 :             return false;
     326             :     }
     327             : 
     328         528 :     return true;
     329             : }
     330             : 
     331         470 : bool Date::IsValidDate() const
     332             : {
     333         470 :     return IsValidDate( GetDay(), GetMonth(), GetYear());
     334             : }
     335             : 
     336             : //static
     337       31888 : bool Date::IsValidDate( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
     338             : {
     339       31888 :     if ( !nMonth || (nMonth > 12) )
     340          26 :         return false;
     341       31862 :     if ( !nDay || (nDay > ImplDaysInMonth( nMonth, nYear )) )
     342           0 :         return false;
     343       31862 :     return true;
     344             : }
     345             : 
     346          12 : bool Date::Normalize()
     347             : {
     348          12 :     sal_uInt16 nDay   = GetDay();
     349          12 :     sal_uInt16 nMonth = GetMonth();
     350          12 :     sal_uInt16 nYear  = GetYear();
     351             : 
     352          12 :     if (!Normalize( nDay, nMonth, nYear))
     353          12 :         return false;
     354             : 
     355           0 :     SetDay( nDay);
     356           0 :     SetMonth( nMonth);
     357           0 :     SetYear( nYear);
     358             : 
     359           0 :     return true;
     360             : }
     361             : 
     362             : //static
     363       31418 : bool Date::Normalize( sal_uInt16 & rDay, sal_uInt16 & rMonth, sal_uInt16 & rYear )
     364             : {
     365       31418 :     if (IsValidDate( rDay, rMonth, rYear))
     366       31392 :         return false;
     367             : 
     368          26 :     if (rMonth > 12)
     369             :     {
     370           0 :         rYear += rMonth / 12;
     371           0 :         rMonth = rMonth % 12;
     372             :     }
     373          26 :     if (!rMonth)
     374             :     {
     375          26 :         if (!rYear)
     376             :         {
     377          26 :             rYear = 0;
     378          26 :             rMonth = 1;
     379          26 :             if (rDay > 31)
     380          22 :                 rDay -= 31;
     381             :             else
     382           4 :                 rDay = 1;
     383             :         }
     384             :         else
     385             :         {
     386           0 :             --rYear;
     387           0 :             rMonth = 12;
     388             :         }
     389             :     }
     390             :     sal_uInt16 nDays;
     391          52 :     while (rDay > (nDays = ImplDaysInMonth( rMonth, rYear)))
     392             :     {
     393           0 :         rDay -= nDays;
     394           0 :         if (rMonth < 12)
     395           0 :             ++rMonth;
     396             :         else
     397             :         {
     398           0 :             ++rYear;
     399           0 :             rMonth = 1;
     400             :         }
     401             :     }
     402          26 :     if (rYear > 9999)
     403             :     {
     404           0 :         rDay = 31;
     405           0 :         rMonth = 12;
     406           0 :         rYear = 9999;
     407             :     }
     408          26 :     return true;
     409             : }
     410             : 
     411       20834 : Date& Date::operator +=( long nDays )
     412             : {
     413             :     sal_uInt16  nDay;
     414             :     sal_uInt16  nMonth;
     415             :     sal_uInt16  nYear;
     416             : 
     417       20834 :     if (nDays == 0)
     418          32 :         return *this;
     419             : 
     420       20802 :     long nTempDays = GetAsNormalizedDays();
     421             : 
     422       20802 :     nTempDays += nDays;
     423       20802 :     if ( nTempDays > MAX_DAYS )
     424           0 :         nDate = 31 + (12*100) + (((sal_uIntPtr)9999)*10000);
     425       20802 :     else if ( nTempDays <= 0 )
     426           0 :         nDate = 1 + 100;
     427             :     else
     428             :     {
     429       20802 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     430       20802 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     431             :     }
     432             : 
     433       20802 :     return *this;
     434             : }
     435             : 
     436         108 : Date& Date::operator -=( long nDays )
     437             : {
     438             :     sal_uInt16  nDay;
     439             :     sal_uInt16  nMonth;
     440             :     sal_uInt16  nYear;
     441             : 
     442         108 :     if (nDays == 0)
     443           0 :         return *this;
     444             : 
     445         108 :     long nTempDays = GetAsNormalizedDays();
     446             : 
     447         108 :     nTempDays -= nDays;
     448         108 :     if ( nTempDays > MAX_DAYS )
     449           0 :         nDate = 31 + (12*100) + (((sal_uIntPtr)9999)*10000);
     450         108 :     else if ( nTempDays <= 0 )
     451           0 :         nDate = 1 + 100;
     452             :     else
     453             :     {
     454         108 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     455         108 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     456             :     }
     457             : 
     458         108 :     return *this;
     459             : }
     460             : 
     461          12 : Date& Date::operator ++()
     462             : {
     463             :     sal_uInt16  nDay;
     464             :     sal_uInt16  nMonth;
     465             :     sal_uInt16  nYear;
     466          12 :     long nTempDays = GetAsNormalizedDays();
     467             : 
     468          12 :     if ( nTempDays < MAX_DAYS )
     469             :     {
     470          12 :         nTempDays++;
     471          12 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     472          12 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     473             :     }
     474             : 
     475          12 :     return *this;
     476             : }
     477             : 
     478           0 : Date& Date::operator --()
     479             : {
     480             :     sal_uInt16  nDay;
     481             :     sal_uInt16  nMonth;
     482             :     sal_uInt16  nYear;
     483           0 :     long nTempDays = GetAsNormalizedDays();
     484             : 
     485           0 :     if ( nTempDays > 1 )
     486             :     {
     487           0 :         nTempDays--;
     488           0 :         DaysToDate( nTempDays, nDay, nMonth, nYear );
     489           0 :         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
     490             :     }
     491           0 :     return *this;
     492             : }
     493             : 
     494           4 : Date Date::operator ++( int )
     495             : {
     496           4 :     Date aOldDate = *this;
     497           4 :     Date::operator++();
     498           4 :     return aOldDate;
     499             : }
     500             : 
     501           0 : Date Date::operator --( int )
     502             : {
     503           0 :     Date aOldDate = *this;
     504           0 :     Date::operator--();
     505           0 :     return aOldDate;
     506             : }
     507             : 
     508       13778 : Date operator +( const Date& rDate, long nDays )
     509             : {
     510       13778 :     Date aDate( rDate );
     511       13778 :     aDate += nDays;
     512       13778 :     return aDate;
     513             : }
     514             : 
     515         108 : Date operator -( const Date& rDate, long nDays )
     516             : {
     517         108 :     Date aDate( rDate );
     518         108 :     aDate -= nDays;
     519         108 :     return aDate;
     520             : }
     521             : 
     522       10710 : long operator -( const Date& rDate1, const Date& rDate2 )
     523             : {
     524       10710 :     sal_uIntPtr nTempDays1 = rDate1.GetAsNormalizedDays();
     525       10710 :     sal_uIntPtr nTempDays2 = rDate2.GetAsNormalizedDays();
     526             : 
     527       10710 :     return nTempDays1 - nTempDays2;
     528             : }
     529             : 
     530             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10