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