1 /* 2 * Copyright 2007-2010 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus, superstippi@gmx.de 7 * Julun, host.haiku@gmx.de 8 */ 9 10 #include "DateTime.h" 11 12 13 #include <time.h> 14 #include <sys/time.h> 15 16 #include <Message.h> 17 18 19 namespace BPrivate { 20 21 const int32 kSecondsPerMinute = 60; 22 23 const int32 kHoursPerDay = 24; 24 const int32 kMinutesPerDay = 1440; 25 const int32 kSecondsPerDay = 86400; 26 const int32 kMillisecondsPerDay = 86400000; 27 28 const bigtime_t kMicrosecondsPerSecond = 1000000LL; 29 const bigtime_t kMicrosecondsPerMinute = 60000000LL; 30 const bigtime_t kMicrosecondsPerHour = 3600000000LL; 31 const bigtime_t kMicrosecondsPerDay = 86400000000LL; 32 33 34 /*! 35 Constructs a new BTime object. Asked for its time representation, it will 36 return 0 for Hour(), Minute(), Second() etc. This can represent midnight, 37 but be aware IsValid() will return false. 38 */ 39 BTime::BTime() 40 : 41 fMicroseconds(-1) 42 { 43 } 44 45 46 /*! 47 Constructs a new BTime object as a copy of \c other. 48 */ 49 BTime::BTime(const BTime& other) 50 : 51 fMicroseconds(other.fMicroseconds) 52 { 53 } 54 55 56 /*! 57 Constructs a BTime object with \c hour \c minute, \c second, \c microsecond. 58 59 \c hour must be between 0 and 23, \c minute and \c second must be between 60 0 and 59 and \c microsecond should be in the range of 0 and 999999. If the 61 specified time is invalid, the time is not set and IsValid() returns false. 62 */ 63 BTime::BTime(int32 hour, int32 minute, int32 second, int32 microsecond) 64 : 65 fMicroseconds(-1) 66 { 67 _SetTime(hour, minute, second, microsecond); 68 } 69 70 71 /*! 72 Constructs a new BTime object from the provided BMessage archive. 73 */ 74 BTime::BTime(const BMessage* archive) 75 : 76 fMicroseconds(-1) 77 { 78 if (archive == NULL) 79 return; 80 archive->FindInt64("microseconds", &fMicroseconds); 81 } 82 83 84 /*! 85 Empty destructor. 86 */ 87 BTime::~BTime() 88 { 89 } 90 91 92 /*! 93 Archives the BTime object into the provided BMessage object. 94 @returns \c B_OK if all went well. 95 \c B_BAD_VALUE, if the message is \c NULL. 96 \c other error codes, depending on failure to append 97 fields to the message. 98 */ 99 status_t 100 BTime::Archive(BMessage* into) const 101 { 102 if (into == NULL) 103 return B_BAD_VALUE; 104 return into->AddInt64("microseconds", fMicroseconds); 105 } 106 107 108 /*! 109 Returns true if the time is valid, otherwise false. A valid time can be 110 BTime(23, 59, 59, 999999) while BTime(24, 00, 01) would be invalid. 111 */ 112 bool 113 BTime::IsValid() const 114 { 115 return fMicroseconds > -1 && fMicroseconds < kMicrosecondsPerDay; 116 } 117 118 119 /*! 120 This is an overloaded member function, provided for convenience. 121 */ 122 /*static*/ bool 123 BTime::IsValid(const BTime& time) 124 { 125 return time.IsValid(); 126 } 127 128 129 /*! 130 This is an overloaded member function, provided for convenience. 131 */ 132 /*static*/ bool 133 BTime::IsValid(int32 hour, int32 minute, int32 second, int32 microsecond) 134 { 135 return BTime(hour, minute, second, microsecond).IsValid(); 136 } 137 138 139 /*! 140 Returns the current time as reported by the system depending on the given 141 time_type \c type. 142 */ 143 BTime 144 BTime::CurrentTime(time_type type) 145 { 146 struct timeval tv; 147 if (gettimeofday(&tv, NULL) != 0) { 148 // gettimeofday failed? 149 time(&tv.tv_sec); 150 } 151 152 struct tm result; 153 struct tm* timeinfo; 154 if (type == B_GMT_TIME) 155 timeinfo = gmtime_r(&tv.tv_sec, &result); 156 else 157 timeinfo = localtime_r(&tv.tv_sec, &result); 158 159 if (timeinfo == NULL) 160 return BTime(); 161 162 int32 sec = timeinfo->tm_sec; 163 return BTime(timeinfo->tm_hour, timeinfo->tm_min, (sec > 59) ? 59 : sec, 164 tv.tv_usec); 165 } 166 167 168 /*! 169 Returns a copy of the current BTime object. 170 */ 171 BTime 172 BTime::Time() const 173 { 174 return *this; 175 } 176 177 178 /*! 179 This is an overloaded member function, provided for convenience. Set the 180 current BTime object to the passed BTime \c time object. 181 */ 182 bool 183 BTime::SetTime(const BTime& time) 184 { 185 fMicroseconds = time.fMicroseconds; 186 return IsValid(); 187 } 188 189 190 /*! 191 Set the time to \c hour \c minute, \c second and \c microsecond. 192 193 \c hour must be between 0 and 23, \c minute and \c second must be between 194 0 and 59 and \c microsecond should be in the range of 0 and 999999. Returns 195 true if the time is valid; otherwise false. If the specified time is 196 invalid, the time is not set and the function returns false. 197 */ 198 bool 199 BTime::SetTime(int32 hour, int32 minute, int32 second, int32 microsecond) 200 { 201 return _SetTime(hour, minute, second, microsecond); 202 } 203 204 205 /*! 206 Adds \c hours to the current time. If the passed value is negative it 207 will become earlier. Note: The time will wrap if it passes midnight. 208 */ 209 BTime& 210 BTime::AddHours(int32 hours) 211 { 212 return _AddMicroseconds(bigtime_t(hours % kHoursPerDay) 213 * kMicrosecondsPerHour); 214 } 215 216 217 /*! 218 Adds \c minutes to the current time. If the passed value is negative it 219 will become earlier. Note: The time will wrap if it passes midnight. 220 */ 221 BTime& 222 BTime::AddMinutes(int32 minutes) 223 { 224 return _AddMicroseconds(bigtime_t(minutes % kMinutesPerDay) 225 * kMicrosecondsPerMinute); 226 } 227 228 229 /*! 230 Adds \c seconds to the current time. If the passed value is negative 231 it will become earlier. Note: The time will wrap if it passes midnight. 232 */ 233 BTime& 234 BTime::AddSeconds(int32 seconds) 235 { 236 return _AddMicroseconds(bigtime_t(seconds % kSecondsPerDay) 237 * kMicrosecondsPerSecond); 238 } 239 240 241 /*! 242 Adds \c milliseconds to the current time. If the passed value is negative 243 it will become earlier. Note: The time will wrap if it passes midnight. 244 */ 245 BTime& 246 BTime::AddMilliseconds(int32 milliseconds) 247 { 248 return _AddMicroseconds(bigtime_t(milliseconds % kMillisecondsPerDay) 249 * 1000); 250 } 251 252 253 /*! 254 Adds \c microseconds to the current time. If the passed value is negative 255 it will become earlier. Note: The time will wrap if it passes midnight. 256 */ 257 BTime& 258 BTime::AddMicroseconds(int32 microseconds) 259 { 260 return _AddMicroseconds(microseconds); 261 } 262 263 264 /*! 265 Returns the hour fragment of the time. 266 */ 267 int32 268 BTime::Hour() const 269 { 270 return int32(_Microseconds() / kMicrosecondsPerHour); 271 } 272 273 274 /*! 275 Returns the minute fragment of the time. 276 */ 277 int32 278 BTime::Minute() const 279 { 280 return int32(((_Microseconds() % kMicrosecondsPerHour)) 281 / kMicrosecondsPerMinute); 282 } 283 284 285 /*! 286 Returns the second fragment of the time. 287 */ 288 int32 289 BTime::Second() const 290 { 291 return int32(_Microseconds() / kMicrosecondsPerSecond) % kSecondsPerMinute; 292 } 293 294 295 /*! 296 Returns the millisecond fragment of the time. 297 */ 298 int32 299 BTime::Millisecond() const 300 { 301 302 return Microsecond() / 1000; 303 } 304 305 306 /*! 307 Returns the microsecond fragment of the time. 308 */ 309 int32 310 BTime::Microsecond() const 311 { 312 return int32(_Microseconds() % kMicrosecondsPerSecond); 313 } 314 315 316 bigtime_t 317 BTime::_Microseconds() const 318 { 319 return fMicroseconds == -1 ? 0 : fMicroseconds; 320 } 321 322 323 /*! 324 Returns the difference between this time and the given BTime \c time based 325 on the passed diff_type \c type. If \c time is earlier the return value will 326 be negativ. 327 328 The return value then can be hours, minutes, seconds, milliseconds or 329 microseconds while its range will always be between -86400000000 and 330 86400000000 depending on diff_type \c type. 331 */ 332 bigtime_t 333 BTime::Difference(const BTime& time, diff_type type) const 334 { 335 bigtime_t diff = time._Microseconds() - _Microseconds(); 336 switch (type) { 337 case B_HOURS_DIFF: 338 diff /= kMicrosecondsPerHour; 339 break; 340 case B_MINUTES_DIFF: 341 diff /= kMicrosecondsPerMinute; 342 break; 343 case B_SECONDS_DIFF: 344 diff /= kMicrosecondsPerSecond; 345 break; 346 case B_MILLISECONDS_DIFF: 347 diff /= 1000; 348 break; 349 case B_MICROSECONDS_DIFF: 350 default: 351 break; 352 } 353 return diff; 354 } 355 356 357 /*! 358 Returns true if this time is different from \c time, otherwise false. 359 */ 360 bool 361 BTime::operator!=(const BTime& time) const 362 { 363 return fMicroseconds != time.fMicroseconds; 364 } 365 366 367 /*! 368 Returns true if this time is equal to \c time, otherwise false. 369 */ 370 bool 371 BTime::operator==(const BTime& time) const 372 { 373 return fMicroseconds == time.fMicroseconds; 374 } 375 376 377 /*! 378 Returns true if this time is earlier than \c time, otherwise false. 379 */ 380 bool 381 BTime::operator<(const BTime& time) const 382 { 383 return fMicroseconds < time.fMicroseconds; 384 } 385 386 387 /*! 388 Returns true if this time is earlier than or equal to \c time, otherwise false. 389 */ 390 bool 391 BTime::operator<=(const BTime& time) const 392 { 393 return fMicroseconds <= time.fMicroseconds; 394 } 395 396 397 /*! 398 Returns true if this time is later than \c time, otherwise false. 399 */ 400 bool 401 BTime::operator>(const BTime& time) const 402 { 403 return fMicroseconds > time.fMicroseconds; 404 } 405 406 407 /*! 408 Returns true if this time is later than or equal to \c time, otherwise false. 409 */ 410 bool 411 BTime::operator>=(const BTime& time) const 412 { 413 return fMicroseconds >= time.fMicroseconds; 414 } 415 416 417 BTime& 418 BTime::_AddMicroseconds(bigtime_t microseconds) 419 { 420 bigtime_t count = 0; 421 if (microseconds < 0) { 422 count = ((kMicrosecondsPerDay - microseconds) / kMicrosecondsPerDay) * 423 kMicrosecondsPerDay; 424 } 425 fMicroseconds = (_Microseconds() + microseconds + count) % kMicrosecondsPerDay; 426 return *this; 427 } 428 429 430 bool 431 BTime::_SetTime(bigtime_t hour, bigtime_t minute, bigtime_t second, 432 bigtime_t microsecond) 433 { 434 fMicroseconds = hour * kMicrosecondsPerHour + 435 minute * kMicrosecondsPerMinute + 436 second * kMicrosecondsPerSecond + 437 microsecond; 438 439 bool isValid = IsValid(); 440 if (!isValid) 441 fMicroseconds = -1; 442 443 return isValid; 444 } 445 446 447 // #pragma mark - BDate 448 449 450 /*! 451 Constructs a new BDate object. IsValid() will return false. 452 */ 453 BDate::BDate() 454 : 455 fDay(-1), 456 fYear(0), 457 fMonth(-1) 458 { 459 } 460 461 462 /*! 463 Constructs a new BDate object as a copy of \c other. 464 */ 465 BDate::BDate(const BDate& other) 466 : 467 fDay(other.fDay), 468 fYear(other.fYear), 469 fMonth(other.fMonth) 470 { 471 } 472 473 474 /*! 475 Constructs a BDate object with \c year \c month and \c day. 476 477 Please note that a date before 1.1.4713 BC, a date with year 0 and a date 478 between 4.10.1582 and 15.10.1582 are considered invalid. If the specified 479 date is invalid, the date is not set and IsValid() returns false. Also note 480 that every passed year will be interpreted as is. 481 482 */ 483 BDate::BDate(int32 year, int32 month, int32 day) 484 { 485 _SetDate(year, month, day); 486 } 487 488 489 BDate::BDate(time_t time, time_type type) 490 { 491 struct tm result; 492 struct tm* timeinfo; 493 494 if (type == B_GMT_TIME) 495 timeinfo = gmtime_r(&time, &result); 496 else 497 timeinfo = localtime_r(&time, &result); 498 499 if (timeinfo != NULL) { 500 _SetDate(timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, 501 timeinfo->tm_mday); 502 } 503 } 504 505 506 /*! 507 Constructs a new BDate object from the provided archive. 508 */ 509 BDate::BDate(const BMessage* archive) 510 : 511 fDay(-1), 512 fYear(0), 513 fMonth(-1) 514 { 515 if (archive == NULL) 516 return; 517 archive->FindInt32("day", &fDay); 518 archive->FindInt32("year", &fYear); 519 archive->FindInt32("month", &fMonth); 520 } 521 522 523 /*! 524 Empty destructor. 525 */ 526 BDate::~BDate() 527 { 528 } 529 530 531 /*! 532 Archives the BDate object into the provided BMessage object. 533 @returns \c B_OK if all went well. 534 \c B_BAD_VALUE, if the message is \c NULL. 535 \c other error codes, depending on failure to append 536 fields to the message. 537 */ 538 status_t 539 BDate::Archive(BMessage* into) const 540 { 541 if (into == NULL) 542 return B_BAD_VALUE; 543 status_t ret = into->AddInt32("day", fDay); 544 if (ret == B_OK) 545 ret = into->AddInt32("year", fYear); 546 if (ret == B_OK) 547 ret = into->AddInt32("month", fMonth); 548 return ret; 549 } 550 551 552 /*! 553 Returns true if the date is valid, otherwise false. 554 555 Please note that a date before 1.1.4713 BC, a date with year 0 and a date 556 between 4.10.1582 and 15.10.1582 are considered invalid. 557 */ 558 bool 559 BDate::IsValid() const 560 { 561 return IsValid(fYear, fMonth, fDay); 562 } 563 564 565 /*! 566 This is an overloaded member function, provided for convenience. 567 */ 568 /*static*/ bool 569 BDate::IsValid(const BDate& date) 570 { 571 return IsValid(date.fYear, date.fMonth, date.fDay); 572 } 573 574 575 /*! 576 This is an overloaded member function, provided for convenience. 577 */ 578 /*static*/ bool 579 BDate::IsValid(int32 year, int32 month, int32 day) 580 { 581 // no year 0 in Julian and nothing before 1.1.4713 BC 582 if (year == 0 || year < -4713) 583 return false; 584 585 if (month < 1 || month > 12) 586 return false; 587 588 if (day < 1 || day > _DaysInMonth(year, month)) 589 return false; 590 591 // 'missing' days between switch julian - gregorian 592 if (year == 1582 && month == 10 && day > 4 && day < 15) 593 return false; 594 595 return true; 596 } 597 598 599 /*! 600 Returns the current date as reported by the system depending on the given 601 time_type \c type. 602 */ 603 BDate 604 BDate::CurrentDate(time_type type) 605 { 606 return BDate(time(NULL), type); 607 } 608 609 610 /*! 611 Returns a copy of the current BTime object. 612 */ 613 BDate 614 BDate::Date() const 615 { 616 return *this; 617 } 618 619 620 /*! 621 This is an overloaded member function, provided for convenience. 622 */ 623 bool 624 BDate::SetDate(const BDate& date) 625 { 626 return _SetDate(date.fYear, date.fMonth, date.fDay); 627 } 628 629 630 /*! 631 Set the date to \c year \c month and \c day. 632 633 Returns true if the date is valid; otherwise false. If the specified date is 634 invalid, the date is not set and the function returns false. 635 */ 636 bool 637 BDate::SetDate(int32 year, int32 month, int32 day) 638 { 639 return _SetDate(year, month, day); 640 } 641 642 643 /*! 644 This function sets the given \c year, \c month and \c day to the 645 representative values of this date. The pointers can be NULL. If the date is 646 invalid, the values will be set to -1 for \c month and \c day, the \c year 647 will be set to 0. 648 */ 649 void 650 BDate::GetDate(int32* year, int32* month, int32* day) const 651 { 652 if (year) 653 *year = fYear; 654 655 if (month) 656 *month = fMonth; 657 658 if (day) 659 *day = fDay; 660 } 661 662 663 /*! 664 Adds \c days to the current date. If the passed value is negative it will 665 become earlier. If the current date is invalid, the \c days are not added. 666 */ 667 void 668 BDate::AddDays(int32 days) 669 { 670 if (IsValid()) 671 *this = JulianDayToDate(DateToJulianDay() + days); 672 } 673 674 675 /*! 676 Adds \c years to the current date. If the passed value is negativ it will 677 become earlier. If the current date is invalid, the \c years are not added. 678 The day/ month combination will be adjusted if it does not exist in the 679 resulting year, so this function will then return the latest valid date. 680 */ 681 void 682 BDate::AddYears(int32 years) 683 { 684 if (IsValid()) { 685 const int32 tmp = fYear; 686 fYear += years; 687 688 if ((tmp > 0 && fYear <= 0) || (tmp < 0 && fYear >= 0)) 689 fYear += (years > 0) ? +1 : -1; 690 691 fDay = min_c(fDay, _DaysInMonth(fYear, fMonth)); 692 } 693 } 694 695 696 /*! 697 Adds \c months to the current date. If the passed value is negativ it will 698 become earlier. If the current date is invalid, the \c months are not added. 699 The day/ month combination will be adjusted if it does not exist in the 700 resulting year, so this function will then return the latest valid date. 701 */ 702 void 703 BDate::AddMonths(int32 months) 704 { 705 if (IsValid()) { 706 const int32 tmp = fYear; 707 fYear += months / 12; 708 fMonth += months % 12; 709 710 if (fMonth > 12) { 711 fYear++; 712 fMonth -= 12; 713 } else if (fMonth < 1) { 714 fYear--; 715 fMonth += 12; 716 } 717 718 if ((tmp > 0 && fYear <= 0) || (tmp < 0 && fYear >= 0)) 719 fYear += (months > 0) ? +1 : -1; 720 721 // 'missing' days between switch julian - gregorian 722 if (fYear == 1582 && fMonth == 10 && fDay > 4 && fDay < 15) 723 fDay = (months > 0) ? 15 : 4; 724 725 fDay = min_c(fDay, _DaysInMonth(fYear, fMonth)); 726 } 727 } 728 729 730 /*! 731 Returns the day fragment of the date. The return value will be in the range 732 of 1 to 31, in case the date is invalid it will be -1. 733 */ 734 int32 735 BDate::Day() const 736 { 737 return fDay; 738 } 739 740 741 /*! 742 Returns the year fragment of the date. If the date is invalid, the function 743 returns 0. 744 */ 745 int32 746 BDate::Year() const 747 { 748 return fYear; 749 } 750 751 752 /*! 753 Returns the month fragment of the date. The return value will be in the 754 range of 1 to 12, in case the date is invalid it will be -1. 755 */ 756 int32 757 BDate::Month() const 758 { 759 return fMonth; 760 } 761 762 763 /*! 764 Returns the difference in days between this date and the given BDate \c date. 765 If \c date is earlier the return value will be negativ. If the calculation 766 is done with an invalid date, the result is undefined. 767 */ 768 int32 769 BDate::Difference(const BDate& date) const 770 { 771 return date.DateToJulianDay() - DateToJulianDay(); 772 } 773 774 775 void 776 BDate::SetDay(int32 day) 777 { 778 fDay = day; 779 } 780 781 782 void 783 BDate::SetMonth(int32 month) 784 { 785 fMonth = month; 786 } 787 788 789 void 790 BDate::SetYear(int32 year) 791 { 792 fYear = year; 793 } 794 795 796 /*! 797 Returns the week number of the date, if the date is invalid it will return 798 B_ERROR. Please note that this function does only work within the Gregorian 799 calendar, thus a date before 15.10.1582 will return B_ERROR. 800 */ 801 int32 802 BDate::WeekNumber() const 803 { 804 /* 805 This algorithm is taken from: 806 Frequently Asked Questions about Calendars 807 Version 2.8 Claus Tøndering 15 December 2005 808 809 Note: it will work only within the Gregorian Calendar 810 */ 811 812 if (!IsValid() || fYear < 1582 813 || (fYear == 1582 && fMonth < 10) 814 || (fYear == 1582 && fMonth == 10 && fDay < 15)) 815 return int32(B_ERROR); 816 817 int32 a; 818 int32 b; 819 int32 s; 820 int32 e; 821 int32 f; 822 823 if (fMonth > 0 && fMonth < 3) { 824 a = fYear - 1; 825 b = (a / 4) - (a / 100) + (a / 400); 826 int32 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a -1) / 400); 827 s = b - c; 828 e = 0; 829 f = fDay - 1 + 31 * (fMonth - 1); 830 } else if (fMonth >= 3 && fMonth <= 12) { 831 a = fYear; 832 b = (a / 4) - (a / 100) + (a / 400); 833 int32 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a -1) / 400); 834 s = b - c; 835 e = s + 1; 836 f = fDay + ((153 * (fMonth - 3) + 2) / 5) + 58 + s; 837 } else 838 return int32(B_ERROR); 839 840 int32 g = (a + b) % 7; 841 int32 d = (f + g - e) % 7; 842 int32 n = f + 3 - d; 843 844 int32 weekNumber; 845 if (n < 0) 846 weekNumber = 53 - (g -s) / 5; 847 else if (n > 364 + s) 848 weekNumber = 1; 849 else 850 weekNumber = n / 7 + 1; 851 852 return weekNumber; 853 } 854 855 856 /*! 857 Returns the day of the week in the range of 1 to 7, while 1 stands for 858 monday. If the date is invalid, the function will return B_ERROR. 859 */ 860 int32 861 BDate::DayOfWeek() const 862 { 863 // http://en.wikipedia.org/wiki/Julian_day#Calculation 864 return IsValid() ? (DateToJulianDay() % 7) + 1 : int32(B_ERROR); 865 } 866 867 868 /*! 869 Returns the day of the year in the range of 1 to 365 (366 in leap years). If 870 the date is invalid, the function will return B_ERROR. 871 */ 872 int32 873 BDate::DayOfYear() const 874 { 875 if (!IsValid()) 876 return int32(B_ERROR); 877 878 return DateToJulianDay() - _DateToJulianDay(fYear, 1, 1) + 1; 879 } 880 881 882 /*! 883 Returns true if the year of this object is a leap year, otherwise false. If 884 the \c year passed is before 4713 BC, the result is undefined. 885 */ 886 bool 887 BDate::IsLeapYear() const 888 { 889 return IsLeapYear(fYear); 890 } 891 892 893 /*! 894 Returns true if the passed \c year is a leap year, otherwise false. If the 895 \c year passed is before 4713 BC, the result is undefined. 896 */ 897 /*static*/ bool 898 BDate::IsLeapYear(int32 year) 899 { 900 if (year < 1582) { 901 if (year < 0) 902 year++; 903 return (year % 4) == 0; 904 } 905 return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0); 906 } 907 908 909 /*! 910 Returns the number of days in the year of the current date. If the date is 911 valid it will return 365 or 366, otherwise B_ERROR; 912 */ 913 int32 914 BDate::DaysInYear() const 915 { 916 if (!IsValid()) 917 return int32(B_ERROR); 918 919 return IsLeapYear(fYear) ? 366 : 365; 920 } 921 922 923 /*! 924 Returns the number of days in the month of the current date. If the date is 925 valid it will return 28 up to 31, otherwise B_ERROR; 926 */ 927 int32 928 BDate::DaysInMonth() const 929 { 930 if (!IsValid()) 931 return int32(B_ERROR); 932 933 return _DaysInMonth(fYear, fMonth); 934 } 935 936 937 /*! 938 Returns the short day name of this object. 939 */ 940 BString 941 BDate::ShortDayName() const 942 { 943 return ShortDayName(DayOfWeek()); 944 } 945 946 947 /*! 948 Returns the short day name in case of an valid day, otherwise an empty 949 string. The passed \c day must be in the range of 1 to 7 while 1 stands for 950 monday. 951 */ 952 /*static*/ BString 953 BDate::ShortDayName(int32 day) 954 { 955 if (day < 1 || day > 7) 956 return BString(); 957 958 tm tm_struct; 959 memset(&tm_struct, 0, sizeof(tm)); 960 tm_struct.tm_wday = day == 7 ? 0 : day; 961 962 char buffer[256]; 963 strftime(buffer, sizeof(buffer), "%a", &tm_struct); 964 965 return BString(buffer); 966 } 967 968 969 /*! 970 Returns the short month name of this object. 971 */ 972 BString 973 BDate::ShortMonthName() const 974 { 975 return ShortMonthName(Month()); 976 } 977 978 979 /*! 980 Returns the short month name in case of an valid month, otherwise an empty 981 string. The passed \c month must be in the range of 1 to 12. 982 */ 983 /*static*/ BString 984 BDate::ShortMonthName(int32 month) 985 { 986 if (month < 1 || month > 12) 987 return BString(); 988 989 tm tm_struct; 990 memset(&tm_struct, 0, sizeof(tm)); 991 tm_struct.tm_mon = month - 1; 992 993 char buffer[256]; 994 strftime(buffer, sizeof(buffer), "%b", &tm_struct); 995 996 return BString(buffer); 997 } 998 999 1000 /*! 1001 Returns the long day name of this object's week day. 1002 */ 1003 BString 1004 BDate::LongDayName() const 1005 { 1006 return LongDayName(DayOfWeek()); 1007 } 1008 1009 1010 /*! 1011 Returns the long day name in case of an valid day, otherwise an empty 1012 string. The passed \c day must be in the range of 1 to 7 while 1 stands for 1013 monday. 1014 */ 1015 /*static*/ BString 1016 BDate::LongDayName(int32 day) 1017 { 1018 if (day < 1 || day > 7) 1019 return BString(); 1020 1021 tm tm_struct; 1022 memset(&tm_struct, 0, sizeof(tm)); 1023 tm_struct.tm_wday = day == 7 ? 0 : day; 1024 1025 char buffer[256]; 1026 strftime(buffer, sizeof(buffer), "%A", &tm_struct); 1027 1028 return BString(buffer); 1029 } 1030 1031 1032 /*! 1033 Returns the long month name of this object's month. 1034 */ 1035 BString 1036 BDate::LongMonthName() const 1037 { 1038 return LongMonthName(Month()); 1039 } 1040 1041 1042 /*! 1043 Returns the long month name in case of an valid month, otherwise an empty 1044 string. The passed \c month must be in the range of 1 to 12. 1045 */ 1046 /*static*/ BString 1047 BDate::LongMonthName(int32 month) 1048 { 1049 if (month < 1 || month > 12) 1050 return BString(); 1051 1052 tm tm_struct; 1053 memset(&tm_struct, 0, sizeof(tm)); 1054 tm_struct.tm_mon = month - 1; 1055 1056 char buffer[256]; 1057 strftime(buffer, sizeof(buffer), "%B", &tm_struct); 1058 1059 return BString(buffer); 1060 } 1061 1062 1063 /*! 1064 Converts the date to Julian day. If your date is invalid, the function will 1065 return B_ERROR. 1066 */ 1067 int32 1068 BDate::DateToJulianDay() const 1069 { 1070 return _DateToJulianDay(fYear, fMonth, fDay); 1071 } 1072 1073 1074 /*! 1075 Converts the passed \c julianDay to an BDate. If the \c julianDay is negativ, 1076 the function will return an invalid date. Because of the switch from Julian 1077 calendar to Gregorian calendar the 4.10.1582 is followed by the 15.10.1582. 1078 */ 1079 /*static*/ BDate 1080 BDate::JulianDayToDate(int32 julianDay) 1081 { 1082 BDate date; 1083 const int32 kGregorianCalendarStart = 2299161; 1084 if (julianDay >= kGregorianCalendarStart) { 1085 // http://en.wikipedia.org/wiki/Julian_day#Gregorian_calendar_from_Julian_day_number 1086 int32 j = julianDay + 32044; 1087 int32 dg = j % 146097; 1088 int32 c = (dg / 36524 + 1) * 3 / 4; 1089 int32 dc = dg - c * 36524; 1090 int32 db = dc % 1461; 1091 int32 a = (db / 365 + 1) * 3 / 4; 1092 int32 da = db - a * 365; 1093 int32 m = (da * 5 + 308) / 153 - 2; 1094 date.fYear = ((j / 146097) * 400 + c * 100 + (dc / 1461) * 4 + a) 1095 - 4800 + (m + 2) / 12; 1096 date.fMonth = (m + 2) % 12 + 1; 1097 date.fDay = int32((da - (m + 4) * 153 / 5 + 122) + 1.5); 1098 } else if (julianDay >= 0) { 1099 // http://en.wikipedia.org/wiki/Julian_day#Calculation 1100 julianDay += 32082; 1101 int32 d = (4 * julianDay + 3) / 1461; 1102 int32 e = julianDay - (1461 * d) / 4; 1103 int32 m = ((5 * e) + 2) / 153; 1104 date.fDay = e - (153 * m + 2) / 5 + 1; 1105 date.fMonth = m + 3 - 12 * (m / 10); 1106 int32 year = d - 4800 + (m / 10); 1107 if (year <= 0) 1108 year--; 1109 date.fYear = year; 1110 } 1111 return date; 1112 } 1113 1114 1115 /*! 1116 Returns true if this date is different from \c date, otherwise false. 1117 */ 1118 bool 1119 BDate::operator!=(const BDate& date) const 1120 { 1121 return DateToJulianDay() != date.DateToJulianDay(); 1122 } 1123 1124 1125 /*! 1126 Returns true if this date is equal to \c date, otherwise false. 1127 */ 1128 bool 1129 BDate::operator==(const BDate& date) const 1130 { 1131 return DateToJulianDay() == date.DateToJulianDay(); 1132 } 1133 1134 1135 /*! 1136 Returns true if this date is earlier than \c date, otherwise false. 1137 */ 1138 bool 1139 BDate::operator<(const BDate& date) const 1140 { 1141 return DateToJulianDay() < date.DateToJulianDay(); 1142 } 1143 1144 1145 /*! 1146 Returns true if this date is earlier than or equal to \c date, otherwise 1147 false. 1148 */ 1149 bool 1150 BDate::operator<=(const BDate& date) const 1151 { 1152 return DateToJulianDay() <= date.DateToJulianDay(); 1153 } 1154 1155 1156 /*! 1157 Returns true if this date is later than \c date, otherwise false. 1158 */ 1159 bool 1160 BDate::operator>(const BDate& date) const 1161 { 1162 return DateToJulianDay() > date.DateToJulianDay(); 1163 } 1164 1165 1166 /*! 1167 Returns true if this date is later than or equal to \c date, otherwise 1168 false. 1169 */ 1170 bool 1171 BDate::operator>=(const BDate& date) const 1172 { 1173 return DateToJulianDay() >= date.DateToJulianDay(); 1174 } 1175 1176 1177 bool 1178 BDate::_SetDate(int32 year, int32 month, int32 day) 1179 { 1180 fDay = -1; 1181 fYear = 0; 1182 fMonth = -1; 1183 1184 bool valid = IsValid(year, month, day); 1185 if (valid) { 1186 fDay = day; 1187 fYear = year; 1188 fMonth = month; 1189 } 1190 1191 return valid; 1192 } 1193 1194 1195 int32 1196 BDate::_DaysInMonth(int32 year, int32 month) 1197 { 1198 if (month == 2 && IsLeapYear(year)) 1199 return 29; 1200 1201 const int32 daysInMonth[12] = 1202 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 1203 1204 return daysInMonth[month -1]; 1205 } 1206 1207 1208 int32 1209 BDate::_DateToJulianDay(int32 _year, int32 month, int32 day) 1210 { 1211 if (IsValid(_year, month, day)) { 1212 int32 year = _year; 1213 if (year < 0) year++; 1214 1215 int32 a = (14 - month) / 12; 1216 int32 y = year + 4800 - a; 1217 int32 m = month + (12 * a) - 3; 1218 1219 // http://en.wikipedia.org/wiki/Julian_day#Calculation 1220 if (year > 1582 1221 || (year == 1582 && month > 10) 1222 || (year == 1582 && month == 10 && day >= 15)) { 1223 return day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - 1224 (y / 100) + (y / 400) - 32045; 1225 } else if (year < 1582 1226 || (year == 1582 && month < 10) 1227 || (year == 1582 && month == 10 && day <= 4)) { 1228 return day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - 32083; 1229 } 1230 } 1231 1232 // http://en.wikipedia.org/wiki/Gregorian_calendar: 1233 // The last day of the Julian calendar was Thursday October 4, 1582 1234 // and this was followed by the first day of the Gregorian calendar, 1235 // Friday October 15, 1582 (the cycle of weekdays was not affected). 1236 return int32(B_ERROR); 1237 } 1238 1239 1240 // #pragma mark - BDateTime 1241 1242 1243 /*! 1244 Constructs a new BDateTime object. IsValid() will return false. 1245 */ 1246 BDateTime::BDateTime() 1247 : fDate(), 1248 fTime() 1249 { 1250 } 1251 1252 1253 /*! 1254 Constructs a BDateTime object with \c date and \c time. The return value 1255 of IsValid() depends on the validity of the passed objects. 1256 */ 1257 BDateTime::BDateTime(const BDate& date, const BTime& time) 1258 : fDate(date), 1259 fTime(time) 1260 { 1261 } 1262 1263 1264 /*! 1265 Constructs a new BDateTime object. IsValid() will return false. 1266 */ 1267 BDateTime::BDateTime(const BMessage* archive) 1268 : fDate(archive), 1269 fTime(archive) 1270 { 1271 } 1272 1273 1274 /*! 1275 Empty destructor. 1276 */ 1277 BDateTime::~BDateTime() 1278 { 1279 } 1280 1281 1282 /*! 1283 Archives the BDateTime object into the provided BMessage object. 1284 @returns \c B_OK if all went well. 1285 \c B_BAD_VALUE, if the message is \c NULL. 1286 \c other error codes, depending on failure to append 1287 fields to the message. 1288 */ 1289 status_t 1290 BDateTime::Archive(BMessage* into) const 1291 { 1292 status_t ret = fDate.Archive(into); 1293 if (ret == B_OK) 1294 ret = fTime.Archive(into); 1295 return ret; 1296 } 1297 1298 1299 /*! 1300 Returns true if the date time is valid, otherwise false. 1301 */ 1302 bool 1303 BDateTime::IsValid() const 1304 { 1305 return fDate.IsValid() && fTime.IsValid(); 1306 } 1307 1308 1309 /*! 1310 Returns the current date and time as reported by the system depending on the 1311 given time_type \c type. 1312 */ 1313 BDateTime 1314 BDateTime::CurrentDateTime(time_type type) 1315 { 1316 return BDateTime(BDate::CurrentDate(type), BTime::CurrentTime(type)); 1317 } 1318 1319 1320 /*! 1321 Sets the current date and time of this object to \c date and \c time. 1322 */ 1323 void 1324 BDateTime::SetDateTime(const BDate& date, const BTime& time) 1325 { 1326 fDate = date; 1327 fTime = time; 1328 } 1329 1330 1331 /*! 1332 Returns the current date of this object. 1333 */ 1334 BDate& 1335 BDateTime::Date() 1336 { 1337 return fDate; 1338 } 1339 1340 1341 /*! 1342 Returns the current date of this object. 1343 */ 1344 const BDate& 1345 BDateTime::Date() const 1346 { 1347 return fDate; 1348 } 1349 1350 1351 /*! 1352 Set the current date of this object to \c date. 1353 */ 1354 void 1355 BDateTime::SetDate(const BDate& date) 1356 { 1357 fDate = date; 1358 } 1359 1360 1361 /*! 1362 Returns the current time of this object. 1363 */ 1364 BTime& 1365 BDateTime::Time() 1366 { 1367 return fTime; 1368 } 1369 1370 1371 /*! 1372 Returns the current time of this object. 1373 */ 1374 const BTime& 1375 BDateTime::Time() const 1376 { 1377 return fTime; 1378 } 1379 1380 1381 /*! 1382 Sets the current time of this object to \c time. 1383 */ 1384 void 1385 BDateTime::SetTime(const BTime& time) 1386 { 1387 fTime = time; 1388 } 1389 1390 1391 /*! 1392 Returns the current date and time converted to seconds since 1393 1.1.1970 - 00:00:00. If the current date is before 1.1.1970 the function 1394 returns -1; 1395 */ 1396 time_t 1397 BDateTime::Time_t() const 1398 { 1399 BDate date(1970, 1, 1); 1400 if (date.Difference(fDate) < 0) 1401 return -1; 1402 1403 tm tm_struct; 1404 1405 tm_struct.tm_hour = fTime.Hour(); 1406 tm_struct.tm_min = fTime.Minute(); 1407 tm_struct.tm_sec = fTime.Second(); 1408 1409 tm_struct.tm_year = fDate.Year() - 1900; 1410 tm_struct.tm_mon = fDate.Month() - 1; 1411 tm_struct.tm_mday = fDate.Day(); 1412 1413 // set less 0 as we won't use it 1414 tm_struct.tm_isdst = -1; 1415 1416 // return secs_since_jan1_1970 or -1 on error 1417 return mktime(&tm_struct); 1418 } 1419 1420 1421 /*! 1422 Sets the current date and time converted from seconds since 1423 1.1.1970 - 00:00:00. 1424 */ 1425 void 1426 BDateTime::SetTime_t(time_t seconds) 1427 { 1428 time_t timePart = seconds % kSecondsPerDay; 1429 if (timePart < 0) { 1430 timePart += kSecondsPerDay; 1431 seconds -= kSecondsPerDay; 1432 } 1433 1434 BTime time; 1435 time.AddSeconds(timePart); 1436 fTime.SetTime(time); 1437 1438 BDate date(1970, 1, 1); 1439 date.AddDays(seconds / kSecondsPerDay); 1440 fDate.SetDate(date); 1441 } 1442 1443 1444 /*! 1445 Returns true if this datetime is different from \c dateTime, otherwise false. 1446 */ 1447 bool 1448 BDateTime::operator!=(const BDateTime& dateTime) const 1449 { 1450 return fTime != dateTime.fTime && fDate != dateTime.fDate; 1451 } 1452 1453 1454 /*! 1455 Returns true if this datetime is equal to \c dateTime, otherwise false. 1456 */ 1457 bool 1458 BDateTime::operator==(const BDateTime& dateTime) const 1459 { 1460 return fTime == dateTime.fTime && fDate == dateTime.fDate; 1461 } 1462 1463 1464 /*! 1465 Returns true if this datetime is earlier than \c dateTime, otherwise false. 1466 */ 1467 bool 1468 BDateTime::operator<(const BDateTime& dateTime) const 1469 { 1470 if (fDate < dateTime.fDate) 1471 return true; 1472 if (fDate == dateTime.fDate) 1473 return fTime < dateTime.fTime; 1474 return false; 1475 } 1476 1477 1478 /*! 1479 Returns true if this datetime is earlier than or equal to \c dateTime, 1480 otherwise false. 1481 */ 1482 bool 1483 BDateTime::operator<=(const BDateTime& dateTime) const 1484 { 1485 if (fDate < dateTime.fDate) 1486 return true; 1487 if (fDate == dateTime.fDate) 1488 return fTime <= dateTime.fTime; 1489 return false; 1490 } 1491 1492 1493 /*! 1494 Returns true if this datetime is later than \c dateTime, otherwise false. 1495 */ 1496 bool 1497 BDateTime::operator>(const BDateTime& dateTime) const 1498 { 1499 if (fDate > dateTime.fDate) 1500 return true; 1501 if (fDate == dateTime.fDate) 1502 return fTime > dateTime.fTime; 1503 return false; 1504 } 1505 1506 1507 /*! 1508 Returns true if this datetime is later than or equal to \c dateTime, 1509 otherwise false. 1510 */ 1511 bool 1512 BDateTime::operator>=(const BDateTime& dateTime) const 1513 { 1514 if (fDate > dateTime.fDate) 1515 return true; 1516 if (fDate == dateTime.fDate) 1517 return fTime >= dateTime.fTime; 1518 return false; 1519 } 1520 1521 } /* namespace BPrivate */ 1522