xref: /trunk/main/tools/source/datetime/tdate.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_tools.hxx"
30 
31 #if defined( OS2 )
32 #define INCL_DOSDATETIME
33 #include <svpm.h>
34 #elif defined( WNT )
35 #ifdef _MSC_VER
36 #pragma warning (push,1)
37 #endif
38 #include <tools/svwin.h>
39 #ifdef _MSC_VER
40 #pragma warning (pop)
41 #endif
42 #else
43 #include <time.h>
44 #endif
45 
46 #include <tools/debug.hxx>
47 #include <tools/date.hxx>
48 #ifdef  MACOSX
49 extern "C" {
50 struct tm *localtime_r(const time_t *timep, struct tm *buffer);
51 }
52 #endif
53 
54 // =======================================================================
55 
56 static sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
57                                    31, 31, 30, 31, 30, 31 };
58 
59 #define MAX_DAYS    3636532
60 
61 // =======================================================================
62 
63 inline sal_Bool ImpIsLeapYear( sal_uInt16 nYear )
64 {
65     return (
66                  ( ((nYear % 4) == 0) && ((nYear % 100) != 0) ) ||
67                  ( (nYear % 400) == 0 )
68                );
69 }
70 
71 // -----------------------------------------------------------------------
72 
73 inline sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
74 {
75     if ( nMonth != 2 )
76         return aDaysInMonth[nMonth-1];
77     else
78     {
79         if (ImpIsLeapYear(nYear))
80             return aDaysInMonth[nMonth-1] + 1;
81         else
82             return aDaysInMonth[nMonth-1];
83     }
84 }
85 
86 // -----------------------------------------------------------------------
87 
88 long Date::DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
89 {
90     long nDays;
91 
92     nDays = ((sal_uIntPtr)nYear-1) * 365;
93     nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
94     for( sal_uInt16 i = 1; i < nMonth; i++ )
95         nDays += DaysInMonth(i,nYear);
96     nDays += nDay;
97     return nDays;
98 }
99 
100 // -----------------------------------------------------------------------
101 
102 static void DaysToDate( long nDays,
103                         sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
104 {
105     long    nTempDays;
106     long    i = 0;
107     sal_Bool    bCalc;
108 
109     do
110     {
111         nTempDays = (long)nDays;
112         rYear = (sal_uInt16)((nTempDays / 365) - i);
113         nTempDays -= ((sal_uIntPtr)rYear-1) * 365;
114         nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
115         bCalc = sal_False;
116         if ( nTempDays < 1 )
117         {
118             i++;
119             bCalc = sal_True;
120         }
121         else
122         {
123             if ( nTempDays > 365 )
124             {
125                 if ( (nTempDays != 366) || !ImpIsLeapYear( rYear ) )
126                 {
127                     i--;
128                     bCalc = sal_True;
129                 }
130             }
131         }
132     }
133     while ( bCalc );
134 
135     rMonth = 1;
136     while ( (sal_uIntPtr)nTempDays > DaysInMonth( rMonth, rYear ) )
137     {
138         nTempDays -= DaysInMonth( rMonth, rYear );
139         rMonth++;
140     }
141     rDay = (sal_uInt16)nTempDays;
142 }
143 
144 // =======================================================================
145 
146 Date::Date()
147 {
148 #if defined( OS2 )
149     DATETIME aDateTime;
150     DosGetDateTime( &aDateTime );
151 
152     // Datum zusammenbauen
153     nDate = ((sal_uIntPtr)aDateTime.day) +
154             (((sal_uIntPtr)aDateTime.month)*100) +
155             (((sal_uIntPtr)aDateTime.year)*10000);
156 #elif defined WNT
157     SYSTEMTIME aDateTime;
158     GetLocalTime( &aDateTime );
159 
160     // Datum zusammenbauen
161     nDate = ((sal_uIntPtr)aDateTime.wDay) +
162             (((sal_uIntPtr)aDateTime.wMonth)*100) +
163             (((sal_uIntPtr)aDateTime.wYear)*10000);
164 #else
165     time_t     nTmpTime;
166     struct tm aTime;
167 
168     // Zeit ermitteln
169     nTmpTime = time( 0 );
170 
171     // Datum zusammenbauen
172     if ( localtime_r( &nTmpTime, &aTime ) )
173     {
174         nDate = ((sal_uIntPtr)aTime.tm_mday) +
175                 (((sal_uIntPtr)(aTime.tm_mon+1))*100) +
176                 (((sal_uIntPtr)(aTime.tm_year+1900))*10000);
177     }
178     else
179         nDate = 1 + 100 + (((sal_uIntPtr)1900)*10000);
180 #endif
181 }
182 
183 // -----------------------------------------------------------------------
184 
185 void Date::SetDay( sal_uInt16 nNewDay )
186 {
187     sal_uIntPtr  nMonth  = GetMonth();
188     sal_uIntPtr  nYear   = GetYear();
189 
190     nDate = ((sal_uIntPtr)(nNewDay%100)) + (nMonth*100) + (nYear*10000);
191 }
192 
193 // -----------------------------------------------------------------------
194 
195 void Date::SetMonth( sal_uInt16 nNewMonth )
196 {
197     sal_uIntPtr  nDay    = GetDay();
198     sal_uIntPtr  nYear   = GetYear();
199 
200     nDate = nDay + (((sal_uIntPtr)(nNewMonth%100))*100) + (nYear*10000);
201 }
202 
203 // -----------------------------------------------------------------------
204 
205 void Date::SetYear( sal_uInt16 nNewYear )
206 {
207     sal_uIntPtr  nDay   = GetDay();
208     sal_uIntPtr  nMonth = GetMonth();
209 
210     nDate = nDay + (nMonth*100) + (((sal_uIntPtr)(nNewYear%10000))*10000);
211 }
212 
213 // -----------------------------------------------------------------------
214 
215 DayOfWeek Date::GetDayOfWeek() const
216 {
217     return (DayOfWeek)((sal_uIntPtr)(DateToDays( GetDay(), GetMonth(), GetYear() )-1) % 7);
218 }
219 
220 // -----------------------------------------------------------------------
221 
222 sal_uInt16 Date::GetDayOfYear() const
223 {
224     sal_uInt16 nDay = GetDay();
225     for( sal_uInt16 i = 1; i < GetMonth(); i++ )
226          nDay = nDay + ::DaysInMonth( i, GetYear() );   // += yields a warning on MSVC, so don't use it
227     return nDay;
228 }
229 
230 // -----------------------------------------------------------------------
231 
232 sal_uInt16 Date::GetWeekOfYear( DayOfWeek eStartDay,
233                             sal_Int16 nMinimumNumberOfDaysInWeek ) const
234 {
235     short nWeek;
236     short n1WDay = (short)Date( 1, 1, GetYear() ).GetDayOfWeek();
237     short nDayOfYear = (short)GetDayOfYear();
238 
239     // Wochentage beginnen bei 0, deshalb einen abziehen
240     nDayOfYear--;
241     // StartDay beruecksichtigen
242     n1WDay = (n1WDay+(7-(short)eStartDay)) % 7;
243 
244     if (nMinimumNumberOfDaysInWeek < 1 || 7 < nMinimumNumberOfDaysInWeek)
245     {
246         DBG_ERRORFILE("Date::GetWeekOfYear: invalid nMinimumNumberOfDaysInWeek");
247         nMinimumNumberOfDaysInWeek = 4;
248     }
249 
250     if ( nMinimumNumberOfDaysInWeek == 1 )
251     {
252         nWeek = ((n1WDay+nDayOfYear)/7) + 1;
253         // 53te-Woche nur dann, wenn wir nicht schon in der ersten
254         // Woche des neuen Jahres liegen
255         if ( nWeek == 54 )
256             nWeek = 1;
257         else if ( nWeek == 53 )
258         {
259             short nDaysInYear = (short)GetDaysInYear();
260             short nDaysNextYear = (short)Date( 1, 1, GetYear()+1 ).GetDayOfWeek();
261             nDaysNextYear = (nDaysNextYear+(7-(short)eStartDay)) % 7;
262             if ( nDayOfYear > (nDaysInYear-nDaysNextYear-1) )
263                 nWeek = 1;
264         }
265     }
266     else if ( nMinimumNumberOfDaysInWeek == 7 )
267     {
268         nWeek = ((n1WDay+nDayOfYear)/7);
269         // Erste Woche eines Jahres entspricht der letzen Woche des
270         // vorherigen Jahres
271         if ( nWeek == 0 )
272         {
273             Date aLastDatePrevYear( 31, 12, GetYear()-1 );
274             nWeek = aLastDatePrevYear.GetWeekOfYear( eStartDay, nMinimumNumberOfDaysInWeek );
275         }
276     }
277     else // ( nMinimumNumberOfDaysInWeek == somehing_else, commentary examples for 4 )
278     {
279         // x_monday - thursday
280         if ( n1WDay < nMinimumNumberOfDaysInWeek )
281             nWeek = 1;
282         // friday
283         else if ( n1WDay == nMinimumNumberOfDaysInWeek )
284             nWeek = 53;
285         // saturday
286         else if ( n1WDay == nMinimumNumberOfDaysInWeek + 1 )
287         {
288             // Jahr nach Schaltjahr
289             if ( Date( 1, 1, GetYear()-1 ).IsLeapYear() )
290                 nWeek = 53;
291             else
292                 nWeek = 52;
293         }
294         // sunday
295         else
296             nWeek = 52;
297 
298         if ( (nWeek == 1) || (nDayOfYear + n1WDay > 6) )
299         {
300             if ( nWeek == 1 )
301                 nWeek += (nDayOfYear + n1WDay) / 7;
302             else
303                 nWeek = (nDayOfYear + n1WDay) / 7;
304             if ( nWeek == 53 )
305             {
306                 // naechster x_Sonntag == erster x_Sonntag im neuen Jahr
307                 //                     == noch gleiche Woche
308                 long nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
309                 nTempDays +=  6 - (GetDayOfWeek()+(7-(short)eStartDay)) % 7;
310                 sal_uInt16  nDay;
311                 sal_uInt16  nMonth;
312                 sal_uInt16  nYear;
313                 DaysToDate( nTempDays, nDay, nMonth, nYear );
314                 nWeek = Date( nDay, nMonth, nYear ).GetWeekOfYear( eStartDay, nMinimumNumberOfDaysInWeek );
315             }
316         }
317     }
318 
319     return (sal_uInt16)nWeek;
320 }
321 
322 // -----------------------------------------------------------------------
323 
324 sal_uInt16 Date::GetDaysInMonth() const
325 {
326     return DaysInMonth( GetMonth(), GetYear() );
327 }
328 
329 // -----------------------------------------------------------------------
330 
331 sal_Bool Date::IsLeapYear() const
332 {
333     sal_uInt16 nYear = GetYear();
334     return ImpIsLeapYear( nYear );
335 }
336 
337 // -----------------------------------------------------------------------
338 
339 sal_Bool Date::IsValid() const
340 {
341     sal_uInt16 nDay   = GetDay();
342     sal_uInt16 nMonth = GetMonth();
343     sal_uInt16 nYear  = GetYear();
344 
345     if ( !nMonth || (nMonth > 12) )
346         return sal_False;
347     if ( !nDay || (nDay > DaysInMonth( nMonth, nYear )) )
348         return sal_False;
349     else if ( nYear <= 1582 )
350     {
351         if ( nYear < 1582 )
352             return sal_False;
353         else if ( nMonth < 10 )
354             return sal_False;
355         else if ( (nMonth == 10) && (nDay < 15) )
356             return sal_False;
357     }
358 
359     return sal_True;
360 }
361 
362 // -----------------------------------------------------------------------
363 
364 Date& Date::operator +=( long nDays )
365 {
366     sal_uInt16  nDay;
367     sal_uInt16  nMonth;
368     sal_uInt16  nYear;
369     long    nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
370 
371     nTempDays += nDays;
372     if ( nTempDays > MAX_DAYS )
373         nDate = 31 + (12*100) + (((sal_uIntPtr)9999)*10000);
374     else if ( nTempDays <= 0 )
375         nDate = 1 + 100;
376     else
377     {
378         DaysToDate( nTempDays, nDay, nMonth, nYear );
379         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
380     }
381 
382     return *this;
383 }
384 
385 // -----------------------------------------------------------------------
386 
387 Date& Date::operator -=( long nDays )
388 {
389     sal_uInt16  nDay;
390     sal_uInt16  nMonth;
391     sal_uInt16  nYear;
392     long    nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
393 
394     nTempDays -= nDays;
395     if ( nTempDays > MAX_DAYS )
396         nDate = 31 + (12*100) + (((sal_uIntPtr)9999)*10000);
397     else if ( nTempDays <= 0 )
398         nDate = 1 + 100;
399     else
400     {
401         DaysToDate( nTempDays, nDay, nMonth, nYear );
402         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
403     }
404 
405     return *this;
406 }
407 
408 // -----------------------------------------------------------------------
409 
410 Date& Date::operator ++()
411 {
412     sal_uInt16  nDay;
413     sal_uInt16  nMonth;
414     sal_uInt16  nYear;
415     long    nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
416 
417     if ( nTempDays < MAX_DAYS )
418     {
419         nTempDays++;
420         DaysToDate( nTempDays, nDay, nMonth, nYear );
421         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
422     }
423 
424     return *this;
425 }
426 
427 // -----------------------------------------------------------------------
428 
429 Date& Date::operator --()
430 {
431     sal_uInt16  nDay;
432     sal_uInt16  nMonth;
433     sal_uInt16  nYear;
434     long    nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
435 
436     if ( nTempDays > 1 )
437     {
438         nTempDays--;
439         DaysToDate( nTempDays, nDay, nMonth, nYear );
440         nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
441     }
442     return *this;
443 }
444 
445 #ifndef MPW33
446 
447 // -----------------------------------------------------------------------
448 
449 Date Date::operator ++( int )
450 {
451     Date aOldDate = *this;
452     Date::operator++();
453     return aOldDate;
454 }
455 
456 // -----------------------------------------------------------------------
457 
458 Date Date::operator --( int )
459 {
460     Date aOldDate = *this;
461     Date::operator--();
462     return aOldDate;
463 }
464 
465 #endif
466 
467 // -----------------------------------------------------------------------
468 
469 Date operator +( const Date& rDate, long nDays )
470 {
471     Date aDate( rDate );
472     aDate += nDays;
473     return aDate;
474 }
475 
476 // -----------------------------------------------------------------------
477 
478 Date operator -( const Date& rDate, long nDays )
479 {
480     Date aDate( rDate );
481     aDate -= nDays;
482     return aDate;
483 }
484 
485 // -----------------------------------------------------------------------
486 
487 long operator -( const Date& rDate1, const Date& rDate2 )
488 {
489     sal_uIntPtr  nTempDays1 = Date::DateToDays( rDate1.GetDay(), rDate1.GetMonth(),
490                                     rDate1.GetYear() );
491     sal_uIntPtr  nTempDays2 = Date::DateToDays( rDate2.GetDay(), rDate2.GetMonth(),
492                                     rDate2.GetYear() );
493     return nTempDays1 - nTempDays2;
494 }
495