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