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