/* * Copyright 2007-2010 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Stephan Aßmus, superstippi@gmx.de * Julun, host.haiku@gmx.de */ #include "DateTime.h" #include #include #include #include #include #include namespace BPrivate { const int32 kSecondsPerMinute = 60; const int32 kHoursPerDay = 24; const int32 kMinutesPerDay = 1440; const int32 kSecondsPerDay = 86400; const int32 kMillisecondsPerDay = 86400000; const bigtime_t kMicrosecondsPerSecond = 1000000LL; const bigtime_t kMicrosecondsPerMinute = 60000000LL; const bigtime_t kMicrosecondsPerHour = 3600000000LL; const bigtime_t kMicrosecondsPerDay = 86400000000LL; /*! Constructs a new BTime object. Asked for its time representation, it will return 0 for Hour(), Minute(), Second() etc. This can represent midnight, but be aware IsValid() will return false. */ BTime::BTime() : fMicroseconds(-1) { } /*! Constructs a new BTime object as a copy of \c other. */ BTime::BTime(const BTime& other) : fMicroseconds(other.fMicroseconds) { } /*! Constructs a BTime object with \c hour \c minute, \c second, \c microsecond. \c hour must be between 0 and 23, \c minute and \c second must be between 0 and 59 and \c microsecond should be in the range of 0 and 999999. If the specified time is invalid, the time is not set and IsValid() returns false. */ BTime::BTime(int32 hour, int32 minute, int32 second, int32 microsecond) : fMicroseconds(-1) { _SetTime(hour, minute, second, microsecond); } /*! Constructs a new BTime object from the provided BMessage archive. */ BTime::BTime(const BMessage* archive) : fMicroseconds(-1) { if (archive == NULL) return; archive->FindInt64("microseconds", &fMicroseconds); } /*! Empty destructor. */ BTime::~BTime() { } /*! Archives the BTime object into the provided BMessage object. @returns \c B_OK if all went well. \c B_BAD_VALUE, if the message is \c NULL. \c other error codes, depending on failure to append fields to the message. */ status_t BTime::Archive(BMessage* into) const { if (into == NULL) return B_BAD_VALUE; return into->AddInt64("microseconds", fMicroseconds); } /*! Returns true if the time is valid, otherwise false. A valid time can be BTime(23, 59, 59, 999999) while BTime(24, 00, 01) would be invalid. */ bool BTime::IsValid() const { return fMicroseconds > -1 && fMicroseconds < kMicrosecondsPerDay; } /*! This is an overloaded member function, provided for convenience. */ /*static*/ bool BTime::IsValid(const BTime& time) { return time.IsValid(); } /*! This is an overloaded member function, provided for convenience. */ /*static*/ bool BTime::IsValid(int32 hour, int32 minute, int32 second, int32 microsecond) { return BTime(hour, minute, second, microsecond).IsValid(); } /*! Returns the current time as reported by the system depending on the given time_type \c type. */ BTime BTime::CurrentTime(time_type type) { struct timeval tv; if (gettimeofday(&tv, NULL) != 0) { // gettimeofday failed? time(&tv.tv_sec); } struct tm result; struct tm* timeinfo; if (type == B_GMT_TIME) timeinfo = gmtime_r(&tv.tv_sec, &result); else timeinfo = localtime_r(&tv.tv_sec, &result); if (timeinfo == NULL) return BTime(); int32 sec = timeinfo->tm_sec; return BTime(timeinfo->tm_hour, timeinfo->tm_min, (sec > 59) ? 59 : sec, tv.tv_usec); } /*! Returns a copy of the current BTime object. */ BTime BTime::Time() const { return *this; } /*! This is an overloaded member function, provided for convenience. Set the current BTime object to the passed BTime \c time object. */ bool BTime::SetTime(const BTime& time) { fMicroseconds = time.fMicroseconds; return IsValid(); } /*! Set the time to \c hour \c minute, \c second and \c microsecond. \c hour must be between 0 and 23, \c minute and \c second must be between 0 and 59 and \c microsecond should be in the range of 0 and 999999. Returns true if the time is valid; otherwise false. If the specified time is invalid, the time is not set and the function returns false. */ bool BTime::SetTime(int32 hour, int32 minute, int32 second, int32 microsecond) { return _SetTime(hour, minute, second, microsecond); } /*! Adds \c hours to the current time. If the passed value is negative it will become earlier. Note: The time will wrap if it passes midnight. */ BTime& BTime::AddHours(int32 hours) { return _AddMicroseconds(bigtime_t(hours % kHoursPerDay) * kMicrosecondsPerHour); } /*! Adds \c minutes to the current time. If the passed value is negative it will become earlier. Note: The time will wrap if it passes midnight. */ BTime& BTime::AddMinutes(int32 minutes) { return _AddMicroseconds(bigtime_t(minutes % kMinutesPerDay) * kMicrosecondsPerMinute); } /*! Adds \c seconds to the current time. If the passed value is negative it will become earlier. Note: The time will wrap if it passes midnight. */ BTime& BTime::AddSeconds(int32 seconds) { return _AddMicroseconds(bigtime_t(seconds % kSecondsPerDay) * kMicrosecondsPerSecond); } /*! Adds \c milliseconds to the current time. If the passed value is negative it will become earlier. Note: The time will wrap if it passes midnight. */ BTime& BTime::AddMilliseconds(int32 milliseconds) { return _AddMicroseconds(bigtime_t(milliseconds % kMillisecondsPerDay) * 1000); } /*! Adds \c microseconds to the current time. If the passed value is negative it will become earlier. Note: The time will wrap if it passes midnight. */ BTime& BTime::AddMicroseconds(int32 microseconds) { return _AddMicroseconds(microseconds); } /*! Returns the hour fragment of the time. */ int32 BTime::Hour() const { return int32(_Microseconds() / kMicrosecondsPerHour); } /*! Returns the minute fragment of the time. */ int32 BTime::Minute() const { return int32(((_Microseconds() % kMicrosecondsPerHour)) / kMicrosecondsPerMinute); } /*! Returns the second fragment of the time. */ int32 BTime::Second() const { return int32(_Microseconds() / kMicrosecondsPerSecond) % kSecondsPerMinute; } /*! Returns the millisecond fragment of the time. */ int32 BTime::Millisecond() const { return Microsecond() / 1000; } /*! Returns the microsecond fragment of the time. */ int32 BTime::Microsecond() const { return int32(_Microseconds() % kMicrosecondsPerSecond); } bigtime_t BTime::_Microseconds() const { return fMicroseconds == -1 ? 0 : fMicroseconds; } /*! Returns the difference between this time and the given BTime \c time based on the passed diff_type \c type. If \c time is earlier the return value will be negativ. The return value then can be hours, minutes, seconds, milliseconds or microseconds while its range will always be between -86400000000 and 86400000000 depending on diff_type \c type. */ bigtime_t BTime::Difference(const BTime& time, diff_type type) const { bigtime_t diff = time._Microseconds() - _Microseconds(); switch (type) { case B_HOURS_DIFF: diff /= kMicrosecondsPerHour; break; case B_MINUTES_DIFF: diff /= kMicrosecondsPerMinute; break; case B_SECONDS_DIFF: diff /= kMicrosecondsPerSecond; break; case B_MILLISECONDS_DIFF: diff /= 1000; break; case B_MICROSECONDS_DIFF: default: break; } return diff; } /*! Returns true if this time is different from \c time, otherwise false. */ bool BTime::operator!=(const BTime& time) const { return fMicroseconds != time.fMicroseconds; } /*! Returns true if this time is equal to \c time, otherwise false. */ bool BTime::operator==(const BTime& time) const { return fMicroseconds == time.fMicroseconds; } /*! Returns true if this time is earlier than \c time, otherwise false. */ bool BTime::operator<(const BTime& time) const { return fMicroseconds < time.fMicroseconds; } /*! Returns true if this time is earlier than or equal to \c time, otherwise false. */ bool BTime::operator<=(const BTime& time) const { return fMicroseconds <= time.fMicroseconds; } /*! Returns true if this time is later than \c time, otherwise false. */ bool BTime::operator>(const BTime& time) const { return fMicroseconds > time.fMicroseconds; } /*! Returns true if this time is later than or equal to \c time, otherwise false. */ bool BTime::operator>=(const BTime& time) const { return fMicroseconds >= time.fMicroseconds; } BTime& BTime::_AddMicroseconds(bigtime_t microseconds) { bigtime_t count = 0; if (microseconds < 0) { count = ((kMicrosecondsPerDay - microseconds) / kMicrosecondsPerDay) * kMicrosecondsPerDay; } fMicroseconds = (_Microseconds() + microseconds + count) % kMicrosecondsPerDay; return *this; } bool BTime::_SetTime(bigtime_t hour, bigtime_t minute, bigtime_t second, bigtime_t microsecond) { fMicroseconds = hour * kMicrosecondsPerHour + minute * kMicrosecondsPerMinute + second * kMicrosecondsPerSecond + microsecond; bool isValid = IsValid(); if (!isValid) fMicroseconds = -1; return isValid; } // #pragma mark - BDate /*! Constructs a new BDate object. IsValid() will return false. */ BDate::BDate() : fDay(-1), fYear(0), fMonth(-1) { } /*! Constructs a new BDate object as a copy of \c other. */ BDate::BDate(const BDate& other) : fDay(other.fDay), fYear(other.fYear), fMonth(other.fMonth) { } /*! Constructs a BDate object with \c year \c month and \c day. Please note that a date before 1.1.4713 BC, a date with year 0 and a date between 4.10.1582 and 15.10.1582 are considered invalid. If the specified date is invalid, the date is not set and IsValid() returns false. Also note that every passed year will be interpreted as is. */ BDate::BDate(int32 year, int32 month, int32 day) { _SetDate(year, month, day); } BDate::BDate(time_t time, time_type type) { struct tm result; struct tm* timeinfo; if (type == B_GMT_TIME) timeinfo = gmtime_r(&time, &result); else timeinfo = localtime_r(&time, &result); if (timeinfo != NULL) { _SetDate(timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday); } } /*! Constructs a new BDate object from the provided archive. */ BDate::BDate(const BMessage* archive) : fDay(-1), fYear(0), fMonth(-1) { if (archive == NULL) return; archive->FindInt32("day", &fDay); archive->FindInt32("year", &fYear); archive->FindInt32("month", &fMonth); } /*! Empty destructor. */ BDate::~BDate() { } /*! Archives the BDate object into the provided BMessage object. @returns \c B_OK if all went well. \c B_BAD_VALUE, if the message is \c NULL. \c other error codes, depending on failure to append fields to the message. */ status_t BDate::Archive(BMessage* into) const { if (into == NULL) return B_BAD_VALUE; status_t ret = into->AddInt32("day", fDay); if (ret == B_OK) ret = into->AddInt32("year", fYear); if (ret == B_OK) ret = into->AddInt32("month", fMonth); return ret; } /*! Returns true if the date is valid, otherwise false. Please note that a date before 1.1.4713 BC, a date with year 0 and a date between 4.10.1582 and 15.10.1582 are considered invalid. */ bool BDate::IsValid() const { return IsValid(fYear, fMonth, fDay); } /*! This is an overloaded member function, provided for convenience. */ /*static*/ bool BDate::IsValid(const BDate& date) { return IsValid(date.fYear, date.fMonth, date.fDay); } /*! This is an overloaded member function, provided for convenience. */ /*static*/ bool BDate::IsValid(int32 year, int32 month, int32 day) { // no year 0 in Julian and nothing before 1.1.4713 BC if (year == 0 || year < -4713) return false; if (month < 1 || month > 12) return false; if (day < 1 || day > _DaysInMonth(year, month)) return false; // 'missing' days between switch julian - gregorian if (year == 1582 && month == 10 && day > 4 && day < 15) return false; return true; } /*! Returns the current date as reported by the system depending on the given time_type \c type. */ BDate BDate::CurrentDate(time_type type) { return BDate(time(NULL), type); } /*! Returns a copy of the current BTime object. */ BDate BDate::Date() const { return *this; } /*! This is an overloaded member function, provided for convenience. */ bool BDate::SetDate(const BDate& date) { return _SetDate(date.fYear, date.fMonth, date.fDay); } /*! Set the date to \c year \c month and \c day. Returns true if the date is valid; otherwise false. If the specified date is invalid, the date is not set and the function returns false. */ bool BDate::SetDate(int32 year, int32 month, int32 day) { return _SetDate(year, month, day); } /*! This function sets the given \c year, \c month and \c day to the representative values of this date. The pointers can be NULL. If the date is invalid, the values will be set to -1 for \c month and \c day, the \c year will be set to 0. */ void BDate::GetDate(int32* year, int32* month, int32* day) const { if (year) *year = fYear; if (month) *month = fMonth; if (day) *day = fDay; } /*! Adds \c days to the current date. If the passed value is negative it will become earlier. If the current date is invalid, the \c days are not added. */ void BDate::AddDays(int32 days) { if (IsValid()) *this = JulianDayToDate(DateToJulianDay() + days); } /*! Adds \c years to the current date. If the passed value is negativ it will become earlier. If the current date is invalid, the \c years are not added. The day/ month combination will be adjusted if it does not exist in the resulting year, so this function will then return the latest valid date. */ void BDate::AddYears(int32 years) { if (IsValid()) { const int32 tmp = fYear; fYear += years; if ((tmp > 0 && fYear <= 0) || (tmp < 0 && fYear >= 0)) fYear += (years > 0) ? +1 : -1; fDay = min_c(fDay, _DaysInMonth(fYear, fMonth)); } } /*! Adds \c months to the current date. If the passed value is negativ it will become earlier. If the current date is invalid, the \c months are not added. The day/ month combination will be adjusted if it does not exist in the resulting year, so this function will then return the latest valid date. */ void BDate::AddMonths(int32 months) { if (IsValid()) { const int32 tmp = fYear; fYear += months / 12; fMonth += months % 12; if (fMonth > 12) { fYear++; fMonth -= 12; } else if (fMonth < 1) { fYear--; fMonth += 12; } if ((tmp > 0 && fYear <= 0) || (tmp < 0 && fYear >= 0)) fYear += (months > 0) ? +1 : -1; // 'missing' days between switch julian - gregorian if (fYear == 1582 && fMonth == 10 && fDay > 4 && fDay < 15) fDay = (months > 0) ? 15 : 4; fDay = min_c(fDay, _DaysInMonth(fYear, fMonth)); } } /*! Returns the day fragment of the date. The return value will be in the range of 1 to 31, in case the date is invalid it will be -1. */ int32 BDate::Day() const { return fDay; } /*! Returns the year fragment of the date. If the date is invalid, the function returns 0. */ int32 BDate::Year() const { return fYear; } /*! Returns the month fragment of the date. The return value will be in the range of 1 to 12, in case the date is invalid it will be -1. */ int32 BDate::Month() const { return fMonth; } /*! Returns the difference in days between this date and the given BDate \c date. If \c date is earlier the return value will be negativ. If the calculation is done with an invalid date, the result is undefined. */ int32 BDate::Difference(const BDate& date) const { return date.DateToJulianDay() - DateToJulianDay(); } void BDate::SetDay(int32 day) { fDay = day; } void BDate::SetMonth(int32 month) { fMonth = month; } void BDate::SetYear(int32 year) { fYear = year; } /*! Returns the week number of the date, if the date is invalid it will return B_ERROR. Please note that this function does only work within the Gregorian calendar, thus a date before 15.10.1582 will return B_ERROR. */ int32 BDate::WeekNumber() const { /* This algorithm is taken from: Frequently Asked Questions about Calendars Version 2.8 Claus Tøndering 15 December 2005 Note: it will work only within the Gregorian Calendar */ if (!IsValid() || fYear < 1582 || (fYear == 1582 && fMonth < 10) || (fYear == 1582 && fMonth == 10 && fDay < 15)) return int32(B_ERROR); int32 a; int32 b; int32 s; int32 e; int32 f; if (fMonth > 0 && fMonth < 3) { a = fYear - 1; b = (a / 4) - (a / 100) + (a / 400); int32 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a -1) / 400); s = b - c; e = 0; f = fDay - 1 + 31 * (fMonth - 1); } else if (fMonth >= 3 && fMonth <= 12) { a = fYear; b = (a / 4) - (a / 100) + (a / 400); int32 c = ((a - 1) / 4) - ((a - 1) / 100) + ((a -1) / 400); s = b - c; e = s + 1; f = fDay + ((153 * (fMonth - 3) + 2) / 5) + 58 + s; } else return int32(B_ERROR); int32 g = (a + b) % 7; int32 d = (f + g - e) % 7; int32 n = f + 3 - d; int32 weekNumber; if (n < 0) weekNumber = 53 - (g -s) / 5; else if (n > 364 + s) weekNumber = 1; else weekNumber = n / 7 + 1; return weekNumber; } /*! Returns the day of the week in the range of 1 to 7, while 1 stands for monday. If the date is invalid, the function will return B_ERROR. */ int32 BDate::DayOfWeek() const { // http://en.wikipedia.org/wiki/Julian_day#Calculation return IsValid() ? (DateToJulianDay() % 7) + 1 : int32(B_ERROR); } /*! Returns the day of the year in the range of 1 to 365 (366 in leap years). If the date is invalid, the function will return B_ERROR. */ int32 BDate::DayOfYear() const { if (!IsValid()) return int32(B_ERROR); return DateToJulianDay() - _DateToJulianDay(fYear, 1, 1) + 1; } /*! Returns true if the year of this object is a leap year, otherwise false. If the \c year passed is before 4713 BC, the result is undefined. */ bool BDate::IsLeapYear() const { return IsLeapYear(fYear); } /*! Returns true if the passed \c year is a leap year, otherwise false. If the \c year passed is before 4713 BC, the result is undefined. */ /*static*/ bool BDate::IsLeapYear(int32 year) { if (year < 1582) { if (year < 0) year++; return (year % 4) == 0; } return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0); } /*! Returns the number of days in the year of the current date. If the date is valid it will return 365 or 366, otherwise B_ERROR; */ int32 BDate::DaysInYear() const { if (!IsValid()) return int32(B_ERROR); return IsLeapYear(fYear) ? 366 : 365; } /*! Returns the number of days in the month of the current date. If the date is valid it will return 28 up to 31, otherwise B_ERROR; */ int32 BDate::DaysInMonth() const { if (!IsValid()) return int32(B_ERROR); return _DaysInMonth(fYear, fMonth); } /*! Returns the short day name of this object. */ BString BDate::ShortDayName() const { return ShortDayName(DayOfWeek()); } /*! Returns the short day name in case of an valid day, otherwise an empty string. The passed \c day must be in the range of 1 to 7 while 1 stands for monday. */ /*static*/ BString BDate::ShortDayName(int32 day) { if (day < 1 || day > 7) return BString(); tm tm_struct; memset(&tm_struct, 0, sizeof(tm)); tm_struct.tm_wday = day == 7 ? 0 : day; char buffer[256]; strftime(buffer, sizeof(buffer), "%a", &tm_struct); return BString(buffer); } /*! Returns the short month name of this object. */ BString BDate::ShortMonthName() const { return ShortMonthName(Month()); } /*! Returns the short month name in case of an valid month, otherwise an empty string. The passed \c month must be in the range of 1 to 12. */ /*static*/ BString BDate::ShortMonthName(int32 month) { if (month < 1 || month > 12) return BString(); tm tm_struct; memset(&tm_struct, 0, sizeof(tm)); tm_struct.tm_mon = month - 1; char buffer[256]; strftime(buffer, sizeof(buffer), "%b", &tm_struct); return BString(buffer); } /*! Returns the long day name of this object's week day. */ BString BDate::LongDayName() const { return LongDayName(DayOfWeek()); } /*! Returns the long day name in case of an valid day, otherwise an empty string. The passed \c day must be in the range of 1 to 7 while 1 stands for monday. */ /*static*/ BString BDate::LongDayName(int32 day) { if (day < 1 || day > 7) return BString(); const BLocale* locale = BLocaleRoster::Default()->GetDefaultLocale(); BDateFormat format(locale); BString out; if (format.GetDayName(day, out, B_LONG_DATE_FORMAT) != B_OK) return BString(); return out; } /*! Returns the long month name of this object's month. */ BString BDate::LongMonthName() const { return LongMonthName(Month()); } /*! Returns the long month name in case of an valid month, otherwise an empty string. The passed \c month must be in the range of 1 to 12. */ /*static*/ BString BDate::LongMonthName(int32 month) { if (month < 1 || month > 12) return BString(); const BLocale* locale = BLocaleRoster::Default()->GetDefaultLocale(); BDateFormat format(locale); BString out; if (format.GetMonthName(month, out, B_LONG_DATE_FORMAT) != B_OK) return BString(); return out; } /*! Converts the date to Julian day. If your date is invalid, the function will return B_ERROR. */ int32 BDate::DateToJulianDay() const { return _DateToJulianDay(fYear, fMonth, fDay); } /*! Converts the passed \c julianDay to an BDate. If the \c julianDay is negativ, the function will return an invalid date. Because of the switch from Julian calendar to Gregorian calendar the 4.10.1582 is followed by the 15.10.1582. */ /*static*/ BDate BDate::JulianDayToDate(int32 julianDay) { BDate date; const int32 kGregorianCalendarStart = 2299161; if (julianDay >= kGregorianCalendarStart) { // http://en.wikipedia.org/wiki/Julian_day#Gregorian_calendar_from_Julian_day_number int32 j = julianDay + 32044; int32 dg = j % 146097; int32 c = (dg / 36524 + 1) * 3 / 4; int32 dc = dg - c * 36524; int32 db = dc % 1461; int32 a = (db / 365 + 1) * 3 / 4; int32 da = db - a * 365; int32 m = (da * 5 + 308) / 153 - 2; date.fYear = ((j / 146097) * 400 + c * 100 + (dc / 1461) * 4 + a) - 4800 + (m + 2) / 12; date.fMonth = (m + 2) % 12 + 1; date.fDay = int32((da - (m + 4) * 153 / 5 + 122) + 1.5); } else if (julianDay >= 0) { // http://en.wikipedia.org/wiki/Julian_day#Calculation julianDay += 32082; int32 d = (4 * julianDay + 3) / 1461; int32 e = julianDay - (1461 * d) / 4; int32 m = ((5 * e) + 2) / 153; date.fDay = e - (153 * m + 2) / 5 + 1; date.fMonth = m + 3 - 12 * (m / 10); int32 year = d - 4800 + (m / 10); if (year <= 0) year--; date.fYear = year; } return date; } /*! Returns true if this date is different from \c date, otherwise false. */ bool BDate::operator!=(const BDate& date) const { return DateToJulianDay() != date.DateToJulianDay(); } /*! Returns true if this date is equal to \c date, otherwise false. */ bool BDate::operator==(const BDate& date) const { return DateToJulianDay() == date.DateToJulianDay(); } /*! Returns true if this date is earlier than \c date, otherwise false. */ bool BDate::operator<(const BDate& date) const { return DateToJulianDay() < date.DateToJulianDay(); } /*! Returns true if this date is earlier than or equal to \c date, otherwise false. */ bool BDate::operator<=(const BDate& date) const { return DateToJulianDay() <= date.DateToJulianDay(); } /*! Returns true if this date is later than \c date, otherwise false. */ bool BDate::operator>(const BDate& date) const { return DateToJulianDay() > date.DateToJulianDay(); } /*! Returns true if this date is later than or equal to \c date, otherwise false. */ bool BDate::operator>=(const BDate& date) const { return DateToJulianDay() >= date.DateToJulianDay(); } bool BDate::_SetDate(int32 year, int32 month, int32 day) { fDay = -1; fYear = 0; fMonth = -1; bool valid = IsValid(year, month, day); if (valid) { fDay = day; fYear = year; fMonth = month; } return valid; } int32 BDate::_DaysInMonth(int32 year, int32 month) { if (month == 2 && IsLeapYear(year)) return 29; const int32 daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; return daysInMonth[month -1]; } int32 BDate::_DateToJulianDay(int32 _year, int32 month, int32 day) { if (IsValid(_year, month, day)) { int32 year = _year; if (year < 0) year++; int32 a = (14 - month) / 12; int32 y = year + 4800 - a; int32 m = month + (12 * a) - 3; // http://en.wikipedia.org/wiki/Julian_day#Calculation if (year > 1582 || (year == 1582 && month > 10) || (year == 1582 && month == 10 && day >= 15)) { return day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - (y / 100) + (y / 400) - 32045; } else if (year < 1582 || (year == 1582 && month < 10) || (year == 1582 && month == 10 && day <= 4)) { return day + (((153 * m) + 2) / 5) + (365 * y) + (y / 4) - 32083; } } // http://en.wikipedia.org/wiki/Gregorian_calendar: // The last day of the Julian calendar was Thursday October 4, 1582 // and this was followed by the first day of the Gregorian calendar, // Friday October 15, 1582 (the cycle of weekdays was not affected). return int32(B_ERROR); } // #pragma mark - BDateTime /*! Constructs a new BDateTime object. IsValid() will return false. */ BDateTime::BDateTime() : fDate(), fTime() { } /*! Constructs a BDateTime object with \c date and \c time. The return value of IsValid() depends on the validity of the passed objects. */ BDateTime::BDateTime(const BDate& date, const BTime& time) : fDate(date), fTime(time) { } /*! Constructs a new BDateTime object. IsValid() will return false. */ BDateTime::BDateTime(const BMessage* archive) : fDate(archive), fTime(archive) { } /*! Empty destructor. */ BDateTime::~BDateTime() { } /*! Archives the BDateTime object into the provided BMessage object. @returns \c B_OK if all went well. \c B_BAD_VALUE, if the message is \c NULL. \c other error codes, depending on failure to append fields to the message. */ status_t BDateTime::Archive(BMessage* into) const { status_t ret = fDate.Archive(into); if (ret == B_OK) ret = fTime.Archive(into); return ret; } /*! Returns true if the date time is valid, otherwise false. */ bool BDateTime::IsValid() const { return fDate.IsValid() && fTime.IsValid(); } /*! Returns the current date and time as reported by the system depending on the given time_type \c type. */ BDateTime BDateTime::CurrentDateTime(time_type type) { return BDateTime(BDate::CurrentDate(type), BTime::CurrentTime(type)); } /*! Sets the current date and time of this object to \c date and \c time. */ void BDateTime::SetDateTime(const BDate& date, const BTime& time) { fDate = date; fTime = time; } /*! Returns the current date of this object. */ BDate& BDateTime::Date() { return fDate; } /*! Returns the current date of this object. */ const BDate& BDateTime::Date() const { return fDate; } /*! Set the current date of this object to \c date. */ void BDateTime::SetDate(const BDate& date) { fDate = date; } /*! Returns the current time of this object. */ BTime& BDateTime::Time() { return fTime; } /*! Returns the current time of this object. */ const BTime& BDateTime::Time() const { return fTime; } /*! Sets the current time of this object to \c time. */ void BDateTime::SetTime(const BTime& time) { fTime = time; } /*! Returns the current date and time converted to seconds since 1.1.1970 - 00:00:00. If the current date is before 1.1.1970 the function returns -1; */ time_t BDateTime::Time_t() const { BDate date(1970, 1, 1); if (date.Difference(fDate) < 0) return -1; tm tm_struct; tm_struct.tm_hour = fTime.Hour(); tm_struct.tm_min = fTime.Minute(); tm_struct.tm_sec = fTime.Second(); tm_struct.tm_year = fDate.Year() - 1900; tm_struct.tm_mon = fDate.Month() - 1; tm_struct.tm_mday = fDate.Day(); // set less 0 as we won't use it tm_struct.tm_isdst = -1; // return secs_since_jan1_1970 or -1 on error return mktime(&tm_struct); } /*! Sets the current date and time converted from seconds since 1.1.1970 - 00:00:00. */ void BDateTime::SetTime_t(time_t seconds) { time_t timePart = seconds % kSecondsPerDay; if (timePart < 0) { timePart += kSecondsPerDay; seconds -= kSecondsPerDay; } BTime time; time.AddSeconds(timePart); fTime.SetTime(time); BDate date(1970, 1, 1); date.AddDays(seconds / kSecondsPerDay); fDate.SetDate(date); } /*! Returns true if this datetime is different from \c dateTime, otherwise false. */ bool BDateTime::operator!=(const BDateTime& dateTime) const { return fTime != dateTime.fTime && fDate != dateTime.fDate; } /*! Returns true if this datetime is equal to \c dateTime, otherwise false. */ bool BDateTime::operator==(const BDateTime& dateTime) const { return fTime == dateTime.fTime && fDate == dateTime.fDate; } /*! Returns true if this datetime is earlier than \c dateTime, otherwise false. */ bool BDateTime::operator<(const BDateTime& dateTime) const { if (fDate < dateTime.fDate) return true; if (fDate == dateTime.fDate) return fTime < dateTime.fTime; return false; } /*! Returns true if this datetime is earlier than or equal to \c dateTime, otherwise false. */ bool BDateTime::operator<=(const BDateTime& dateTime) const { if (fDate < dateTime.fDate) return true; if (fDate == dateTime.fDate) return fTime <= dateTime.fTime; return false; } /*! Returns true if this datetime is later than \c dateTime, otherwise false. */ bool BDateTime::operator>(const BDateTime& dateTime) const { if (fDate > dateTime.fDate) return true; if (fDate == dateTime.fDate) return fTime > dateTime.fTime; return false; } /*! Returns true if this datetime is later than or equal to \c dateTime, otherwise false. */ bool BDateTime::operator>=(const BDateTime& dateTime) const { if (fDate > dateTime.fDate) return true; if (fDate == dateTime.fDate) return fTime >= dateTime.fTime; return false; } } /* namespace BPrivate */