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