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