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