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