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