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