Branch data 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 : 55309 : inline sal_Bool ImpIsLeapYear( sal_uInt16 nYear )
41 : : {
42 : : return ( ( ((nYear % 4) == 0) && ((nYear % 100) != 0) ) ||
43 [ + + ][ + + ]: 55309 : ( (nYear % 400) == 0 ) );
[ + + ]
44 : : }
45 : :
46 : : // All callers must have sanitized or normalized month and year values!
47 : 592200 : inline sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
48 : : {
49 [ + + ]: 592200 : if ( nMonth != 2 )
50 : 536891 : return aDaysInMonth[nMonth-1];
51 : : else
52 : : {
53 [ + + ]: 55309 : if (ImpIsLeapYear(nYear))
54 : 21822 : return aDaysInMonth[nMonth-1] + 1;
55 : : else
56 : 592200 : return aDaysInMonth[nMonth-1];
57 : : }
58 : : }
59 : :
60 : 43543 : long Date::DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
61 : : {
62 : : long nDays;
63 : :
64 : 43543 : Normalize( nDay, nMonth, nYear);
65 : :
66 : 43543 : nDays = ((sal_uIntPtr)nYear-1) * 365;
67 : 43543 : nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
68 [ + + ]: 389517 : for( sal_uInt16 i = 1; i < nMonth; i++ )
69 : 345974 : nDays += DaysInMonth(i,nYear);
70 : 43543 : nDays += nDay;
71 : 43543 : return nDays;
72 : : }
73 : :
74 : 18670 : static void DaysToDate( long nDays,
75 : : sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
76 : : {
77 : : long nTempDays;
78 : 18670 : long i = 0;
79 : : sal_Bool bCalc;
80 : :
81 [ + + ]: 28374 : do
82 : : {
83 : 28374 : nTempDays = (long)nDays;
84 : 28374 : rYear = (sal_uInt16)((nTempDays / 365) - i);
85 : 28374 : nTempDays -= ((sal_uIntPtr)rYear-1) * 365;
86 : 28374 : nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
87 : 28374 : bCalc = sal_False;
88 [ + + ]: 28374 : if ( nTempDays < 1 )
89 : : {
90 : 9704 : i++;
91 : 9704 : bCalc = sal_True;
92 : : }
93 : : else
94 : : {
95 [ - + ]: 18670 : 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 : 18670 : rMonth = 1;
108 [ + + ]: 106533 : while ( (sal_uIntPtr)nTempDays > DaysInMonth( rMonth, rYear ) )
109 : : {
110 : 87863 : nTempDays -= DaysInMonth( rMonth, rYear );
111 : 87863 : rMonth++;
112 : : }
113 : 18670 : rDay = (sal_uInt16)nTempDays;
114 : 18670 : }
115 : :
116 : 21034 : 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 : 21034 : nTmpTime = time( 0 );
132 : :
133 : : // compute date
134 [ + - ]: 21034 : if ( localtime_r( &nTmpTime, &aTime ) )
135 : : {
136 : : nDate = ((sal_uIntPtr)aTime.tm_mday) +
137 : : (((sal_uIntPtr)(aTime.tm_mon+1))*100) +
138 : 21034 : (((sal_uIntPtr)(aTime.tm_year+1900))*10000);
139 : : }
140 : : else
141 : 0 : nDate = 1 + 100 + (((sal_uIntPtr)1900)*10000);
142 : : #endif
143 : 21034 : }
144 : :
145 : 48 : void Date::SetDay( sal_uInt16 nNewDay )
146 : : {
147 : 48 : sal_uIntPtr nMonth = GetMonth();
148 : 48 : sal_uIntPtr nYear = GetYear();
149 : :
150 : 48 : nDate = ((sal_uIntPtr)(nNewDay%100)) + (nMonth*100) + (nYear*10000);
151 : 48 : }
152 : :
153 : 44 : void Date::SetMonth( sal_uInt16 nNewMonth )
154 : : {
155 : 44 : sal_uIntPtr nDay = GetDay();
156 : 44 : sal_uIntPtr nYear = GetYear();
157 : :
158 : 44 : nDate = nDay + (((sal_uIntPtr)(nNewMonth%100))*100) + (nYear*10000);
159 : 44 : }
160 : :
161 : 454 : void Date::SetYear( sal_uInt16 nNewYear )
162 : : {
163 : 454 : sal_uIntPtr nDay = GetDay();
164 : 454 : sal_uIntPtr nMonth = GetMonth();
165 : :
166 : 454 : nDate = nDay + (nMonth*100) + (((sal_uIntPtr)(nNewYear%10000))*10000);
167 : 454 : }
168 : :
169 : 35 : DayOfWeek Date::GetDayOfWeek() const
170 : : {
171 : 35 : return (DayOfWeek)((sal_uIntPtr)(DateToDays( GetDay(), GetMonth(), GetYear() )-1) % 7);
172 : : }
173 : :
174 : 60 : sal_uInt16 Date::GetDayOfYear() const
175 : : {
176 : 60 : sal_uInt16 nDay = GetDay();
177 : 60 : sal_uInt16 nMonth = GetMonth();
178 : 60 : sal_uInt16 nYear = GetYear();
179 [ + - ]: 60 : Normalize( nDay, nMonth, nYear);
180 : :
181 [ + + ]: 195 : for( sal_uInt16 i = 1; i < nMonth; i++ )
182 : 135 : nDay = nDay + ::DaysInMonth( i, nYear ); // += yields a warning on MSVC, so don't use it
183 : 60 : 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 : 3653 : sal_uInt16 Date::GetDaysInMonth() const
276 : : {
277 : 3653 : sal_uInt16 nDay = GetDay();
278 : 3653 : sal_uInt16 nMonth = GetMonth();
279 : 3653 : sal_uInt16 nYear = GetYear();
280 [ + - ]: 3653 : Normalize( nDay, nMonth, nYear);
281 : :
282 : 3653 : 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 : 90 : sal_Bool Date::IsValidAndGregorian() const
292 : : {
293 : 90 : sal_uInt16 nDay = GetDay();
294 : 90 : sal_uInt16 nMonth = GetMonth();
295 : 90 : sal_uInt16 nYear = GetYear();
296 : :
297 [ - + ][ + + ]: 90 : if ( !nMonth || (nMonth > 12) )
298 : 10 : return sal_False;
299 [ + - ][ - + ]: 80 : if ( !nDay || (nDay > DaysInMonth( nMonth, nYear )) )
[ - + ]
300 : 0 : return sal_False;
301 [ - + ]: 80 : 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 : 90 : return sal_True;
312 : : }
313 : :
314 : 638 : bool Date::IsValidDate() const
315 : : {
316 : 638 : return IsValidDate( GetDay(), GetMonth(), GetYear());
317 : : }
318 : :
319 : : //static
320 : 47934 : bool Date::IsValidDate( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
321 : : {
322 [ + + ][ + + ]: 47934 : if ( !nMonth || (nMonth > 12) )
323 : 60 : return false;
324 [ + - ][ - + ]: 47874 : if ( !nDay || (nDay > DaysInMonth( nMonth, nYear )) )
[ - + ]
325 : 0 : return false;
326 : 47934 : return true;
327 : : }
328 : :
329 : 40 : bool Date::Normalize()
330 : : {
331 : 40 : sal_uInt16 nDay = GetDay();
332 : 40 : sal_uInt16 nMonth = GetMonth();
333 : 40 : sal_uInt16 nYear = GetYear();
334 : :
335 [ + - ][ + - ]: 40 : if (!Normalize( nDay, nMonth, nYear))
336 : 40 : return false;
337 : :
338 [ # # ]: 0 : SetDay( nDay);
339 [ # # ]: 0 : SetMonth( nMonth);
340 [ # # ]: 0 : SetYear( nYear);
341 : :
342 : 40 : return true;
343 : : }
344 : :
345 : : //static
346 : 47296 : bool Date::Normalize( sal_uInt16 & rDay, sal_uInt16 & rMonth, sal_uInt16 & rYear )
347 : : {
348 [ + + ]: 47296 : if (IsValidDate( rDay, rMonth, rYear))
349 : 47248 : return false;
350 : :
351 [ + + ]: 48 : if (rMonth > 12)
352 : : {
353 : 44 : rYear += rMonth / 12;
354 : 44 : rMonth = rMonth % 12;
355 : : }
356 [ + + ]: 48 : if (!rMonth)
357 : : {
358 [ + - ]: 4 : if (!rYear)
359 : : {
360 : 4 : rYear = 0;
361 : 4 : rMonth = 1;
362 [ - + ]: 4 : if (rDay > 31)
363 : 0 : rDay -= 31;
364 : : else
365 : 4 : rDay = 1;
366 : : }
367 : : else
368 : : {
369 : 0 : --rYear;
370 : 0 : rMonth = 12;
371 : : }
372 : : }
373 : : sal_uInt16 nDays;
374 [ + + ]: 88 : while (rDay > (nDays = DaysInMonth( rMonth, rYear)))
375 : : {
376 : 40 : rDay -= nDays;
377 [ + - ]: 40 : if (rMonth < 12)
378 : 40 : ++rMonth;
379 : : else
380 : : {
381 : 0 : ++rYear;
382 : 0 : rMonth = 1;
383 : : }
384 : : }
385 [ - + ]: 48 : if (rYear > 9999)
386 : : {
387 : 0 : rDay = 31;
388 : 0 : rMonth = 12;
389 : 0 : rYear = 9999;
390 : : }
391 : 47296 : return true;
392 : : }
393 : :
394 : 18599 : Date& Date::operator +=( long nDays )
395 : : {
396 : : sal_uInt16 nDay;
397 : : sal_uInt16 nMonth;
398 : : sal_uInt16 nYear;
399 [ + - ]: 18599 : long nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
400 : :
401 : 18599 : nTempDays += nDays;
402 [ - + ]: 18599 : if ( nTempDays > MAX_DAYS )
403 : 0 : nDate = 31 + (12*100) + (((sal_uIntPtr)9999)*10000);
404 [ - + ]: 18599 : else if ( nTempDays <= 0 )
405 : 0 : nDate = 1 + 100;
406 : : else
407 : : {
408 : 18599 : DaysToDate( nTempDays, nDay, nMonth, nYear );
409 : 18599 : nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
410 : : }
411 : :
412 : 18599 : return *this;
413 : : }
414 : :
415 : 30 : Date& Date::operator -=( long nDays )
416 : : {
417 : : sal_uInt16 nDay;
418 : : sal_uInt16 nMonth;
419 : : sal_uInt16 nYear;
420 [ + - ]: 30 : long nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
421 : :
422 : 30 : nTempDays -= nDays;
423 [ - + ]: 30 : if ( nTempDays > MAX_DAYS )
424 : 0 : nDate = 31 + (12*100) + (((sal_uIntPtr)9999)*10000);
425 [ - + ]: 30 : else if ( nTempDays <= 0 )
426 : 0 : nDate = 1 + 100;
427 : : else
428 : : {
429 : 30 : DaysToDate( nTempDays, nDay, nMonth, nYear );
430 : 30 : nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
431 : : }
432 : :
433 : 30 : return *this;
434 : : }
435 : :
436 : 41 : Date& Date::operator ++()
437 : : {
438 : : sal_uInt16 nDay;
439 : : sal_uInt16 nMonth;
440 : : sal_uInt16 nYear;
441 [ + - ]: 41 : long nTempDays = DateToDays( GetDay(), GetMonth(), GetYear() );
442 : :
443 [ + - ]: 41 : if ( nTempDays < MAX_DAYS )
444 : : {
445 : 41 : nTempDays++;
446 : 41 : DaysToDate( nTempDays, nDay, nMonth, nYear );
447 : 41 : nDate = ((sal_uIntPtr)nDay) + (((sal_uIntPtr)nMonth)*100) + (((sal_uIntPtr)nYear)*10000);
448 : : }
449 : :
450 : 41 : 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 : : #ifndef MPW33
470 : 4 : Date Date::operator ++( int )
471 : : {
472 : 4 : Date aOldDate = *this;
473 : 4 : Date::operator++();
474 : 4 : return aOldDate;
475 : : }
476 : :
477 : 0 : Date Date::operator --( int )
478 : : {
479 : 0 : Date aOldDate = *this;
480 : 0 : Date::operator--();
481 : 0 : return aOldDate;
482 : : }
483 : : #endif
484 : :
485 : 6722 : Date operator +( const Date& rDate, long nDays )
486 : : {
487 : 6722 : Date aDate( rDate );
488 : 6722 : aDate += nDays;
489 : 6722 : return aDate;
490 : : }
491 : :
492 : 30 : Date operator -( const Date& rDate, long nDays )
493 : : {
494 : 30 : Date aDate( rDate );
495 : 30 : aDate -= nDays;
496 : 30 : return aDate;
497 : : }
498 : :
499 : 12419 : long operator -( const Date& rDate1, const Date& rDate2 )
500 : : {
501 : 12419 : sal_uIntPtr nTempDays1 = Date::DateToDays( rDate1.GetDay(), rDate1.GetMonth(),
502 : 24838 : rDate1.GetYear() );
503 : 12419 : sal_uIntPtr nTempDays2 = Date::DateToDays( rDate2.GetDay(), rDate2.GetMonth(),
504 : 24838 : rDate2.GetYear() );
505 : 12419 : return nTempDays1 - nTempDays2;
506 : : }
507 : :
508 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|