* implement julian day handling
* more get/ set functions, operators * date until 1582 are handled in julian calendar * date above 1582 are handled in gregorian calendar git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27264 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -47,9 +47,16 @@ class BDate {
|
|||||||
~BDate();
|
~BDate();
|
||||||
|
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
bool IsValid(const BDate& date) const;
|
||||||
|
bool IsValid(int32 year, int32 month, int32 day) const;
|
||||||
|
|
||||||
static BDate CurrentDate(time_type type);
|
static BDate CurrentDate(time_type type);
|
||||||
|
|
||||||
|
BDate Date() const;
|
||||||
|
bool SetDate(const BDate& date);
|
||||||
|
|
||||||
bool SetDate(int32 year, int32 month, int32 day);
|
bool SetDate(int32 year, int32 month, int32 day);
|
||||||
|
void GetDate(int32* year, int32* month, int32* day);
|
||||||
|
|
||||||
void AddDays(int32 days);
|
void AddDays(int32 days);
|
||||||
void AddYears(int32 years);
|
void AddYears(int32 years);
|
||||||
@@ -58,6 +65,7 @@ class BDate {
|
|||||||
int32 Day() const;
|
int32 Day() const;
|
||||||
int32 Year() const;
|
int32 Year() const;
|
||||||
int32 Month() const;
|
int32 Month() const;
|
||||||
|
int32 Difference(const BDate& date) const;
|
||||||
|
|
||||||
int32 DayOfWeek() const;
|
int32 DayOfWeek() const;
|
||||||
int32 DayOfYear() const;
|
int32 DayOfYear() const;
|
||||||
@@ -74,6 +82,23 @@ class BDate {
|
|||||||
BString LongDayName(int32 day) const;
|
BString LongDayName(int32 day) const;
|
||||||
BString LongMonthName(int32 month) const;
|
BString LongMonthName(int32 month) const;
|
||||||
|
|
||||||
|
int32 DateToJulianDay() const;
|
||||||
|
static BDate JulianDayToDate(int32 julianDay);
|
||||||
|
|
||||||
|
bool operator!=(const BDate& date) const;
|
||||||
|
bool operator==(const BDate& date) const;
|
||||||
|
|
||||||
|
bool operator<(const BDate& date) const;
|
||||||
|
bool operator<=(const BDate& date) const;
|
||||||
|
|
||||||
|
bool operator>(const BDate& date) const;
|
||||||
|
bool operator>=(const BDate& date) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 _DaysInMonth(int32 year, int32 month) const;
|
||||||
|
bool _SetDate(int32 year, int32 month, int32 day);
|
||||||
|
int32 _DateToJulianDay(int32 year, int32 month, int32 day) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int32 fDay;
|
int32 fDay;
|
||||||
int32 fYear;
|
int32 fYear;
|
||||||
|
|||||||
+230
-107
@@ -7,7 +7,7 @@
|
|||||||
* Stephan Aßmus <[email protected]>
|
* Stephan Aßmus <[email protected]>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "DateTime.h"
|
#include <DateTime.h>
|
||||||
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -104,7 +104,7 @@ BTime::Second() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark - BDate
|
||||||
|
|
||||||
|
|
||||||
BDate::BDate()
|
BDate::BDate()
|
||||||
@@ -116,10 +116,8 @@ BDate::BDate()
|
|||||||
|
|
||||||
|
|
||||||
BDate::BDate(int32 year, int32 month, int32 day)
|
BDate::BDate(int32 year, int32 month, int32 day)
|
||||||
: fDay(day),
|
|
||||||
fYear(year),
|
|
||||||
fMonth(month)
|
|
||||||
{
|
{
|
||||||
|
_SetDate(year, month, day);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -131,15 +129,34 @@ BDate::~BDate()
|
|||||||
bool
|
bool
|
||||||
BDate::IsValid() const
|
BDate::IsValid() const
|
||||||
{
|
{
|
||||||
// fail if the year goes less 1583
|
return IsValid(fYear, fMonth, fDay);
|
||||||
// 10/15/1582 start of Gregorian calendar
|
}
|
||||||
if (fYear < 1583)
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDate::IsValid(const BDate& date) const
|
||||||
|
{
|
||||||
|
return IsValid(date.fYear, date.fMonth, date.fDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDate::IsValid(int32 year, int32 month, int32 day) const
|
||||||
|
{
|
||||||
|
// no year 0 in Julian and we can't handle nothing before 1.1.4713 BC
|
||||||
|
if (year == 0 || year < -4713
|
||||||
|
|| (year == -4713 && month < 1)
|
||||||
|
|| (year == -4713 && month < 1 && day < 1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (fMonth < 1 || fMonth > 12)
|
// 'missing' days between switch julian - gregorian
|
||||||
|
if (year == 1582 && month == 10 && day > 4 && day < 15)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (fDay < 1 || fDay > DaysInMonth())
|
if (month < 1 || month > 12)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (day < 1 || day > _DaysInMonth(year, month))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -164,41 +181,45 @@ BDate::CurrentDate(time_type type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BDate
|
||||||
|
BDate::Date() const
|
||||||
|
{
|
||||||
|
return BDate(fYear, fMonth, fDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDate::SetDate(const BDate& date)
|
||||||
|
{
|
||||||
|
return _SetDate(date.fYear, fMonth, fDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BDate::SetDate(int32 year, int32 month, int32 day)
|
BDate::SetDate(int32 year, int32 month, int32 day)
|
||||||
{
|
{
|
||||||
fDay = day;
|
return _SetDate(year, month, day);
|
||||||
fYear = year;
|
}
|
||||||
fMonth = month;
|
|
||||||
|
|
||||||
return IsValid();
|
|
||||||
|
void
|
||||||
|
BDate::GetDate(int32* year, int32* month, int32* day)
|
||||||
|
{
|
||||||
|
if (year)
|
||||||
|
*year = fYear;
|
||||||
|
|
||||||
|
if (month)
|
||||||
|
*month = fMonth;
|
||||||
|
|
||||||
|
if (day)
|
||||||
|
*day = fDay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BDate::AddDays(int32 days)
|
BDate::AddDays(int32 days)
|
||||||
{
|
{
|
||||||
days += Day();
|
*this = JulianDayToDate(DateToJulianDay() + days);
|
||||||
if (days > 0) {
|
|
||||||
while (days > DaysInMonth()) {
|
|
||||||
days -= DaysInMonth();
|
|
||||||
fMonth ++;
|
|
||||||
if (fMonth == 13) {
|
|
||||||
fMonth = 1;
|
|
||||||
fYear ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (days <= 0) {
|
|
||||||
fMonth --;
|
|
||||||
if (fMonth == 0) {
|
|
||||||
fMonth = 12;
|
|
||||||
fYear --;
|
|
||||||
}
|
|
||||||
days += DaysInMonth();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fDay = days;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -206,38 +227,22 @@ void
|
|||||||
BDate::AddYears(int32 years)
|
BDate::AddYears(int32 years)
|
||||||
{
|
{
|
||||||
fYear += years;
|
fYear += years;
|
||||||
fDay = min_c(fDay, DaysInMonth());
|
fDay = min_c(fDay, _DaysInMonth(fYear, fMonth));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BDate::AddMonths(int32 months)
|
BDate::AddMonths(int32 months)
|
||||||
{
|
{
|
||||||
if (months == 0)
|
fYear += months / 12;
|
||||||
return;
|
fMonth += months % 12;
|
||||||
|
|
||||||
if (months > 0) {
|
if (fMonth > 12) {
|
||||||
while (months > 0) {
|
fYear++;
|
||||||
fYear++;
|
fMonth -= 12;
|
||||||
months -= 12;
|
} else if (fMonth < 1) {
|
||||||
}
|
fYear--;
|
||||||
|
fMonth += 12;
|
||||||
fMonth += months;
|
|
||||||
if (fMonth < 1) {
|
|
||||||
fYear--;
|
|
||||||
fMonth += 12;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (months < 0) {
|
|
||||||
fYear--;
|
|
||||||
months += 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
fMonth += months;
|
|
||||||
if (fMonth > 12) {
|
|
||||||
fYear++;
|
|
||||||
fMonth -= 12;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fDay = min_c(fDay, DaysInMonth());
|
fDay = min_c(fDay, DaysInMonth());
|
||||||
}
|
}
|
||||||
@@ -264,6 +269,13 @@ BDate::Month() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BDate::Difference(const BDate& date) const
|
||||||
|
{
|
||||||
|
return DateToJulianDay() - date.DateToJulianDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int32
|
int32
|
||||||
BDate::WeekNumber() const
|
BDate::WeekNumber() const
|
||||||
{
|
{
|
||||||
@@ -275,7 +287,9 @@ BDate::WeekNumber() const
|
|||||||
Note: it will work only within the Gregorian Calendar
|
Note: it will work only within the Gregorian Calendar
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!IsValid())
|
if (!IsValid() || fYear < 1582
|
||||||
|
|| (fYear == 1582 && fMonth < 10)
|
||||||
|
|| (fYear == 1582 && fMonth == 10 && fDay < 15))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int32 a;
|
int32 a;
|
||||||
@@ -320,56 +334,25 @@ BDate::WeekNumber() const
|
|||||||
int32
|
int32
|
||||||
BDate::DayOfWeek() const
|
BDate::DayOfWeek() const
|
||||||
{
|
{
|
||||||
/*
|
// http://en.wikipedia.org/wiki/Julian_day#Calculation
|
||||||
This algorithm is taken from:
|
return (DateToJulianDay() % 7) + 1;
|
||||||
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())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int32 a = (14 - fMonth) / 12;
|
|
||||||
int32 y = fYear - a;
|
|
||||||
int32 m = fMonth + 12 * a - 2;
|
|
||||||
int32 d = (fDay + y + (y / 4) - (y / 100) + (y / 400) + ((31 * m) / 12)) % 7;
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32
|
int32
|
||||||
BDate::DayOfYear() const
|
BDate::DayOfYear() const
|
||||||
{
|
{
|
||||||
/*
|
return DateToJulianDay() - _DateToJulianDay(fYear, 1, 1) + 1;
|
||||||
Note: this function might fail for 1582...
|
|
||||||
|
|
||||||
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).
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!IsValid())
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
const int kFirstDayOfMonth[2][12] = {
|
|
||||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
|
|
||||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
|
|
||||||
};
|
|
||||||
|
|
||||||
if (IsLeapYear(fYear))
|
|
||||||
return kFirstDayOfMonth[1][fMonth -1] + fDay;
|
|
||||||
|
|
||||||
return kFirstDayOfMonth[0][fMonth -1] + fDay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BDate::IsLeapYear(int32 year) const
|
BDate::IsLeapYear(int32 year) const
|
||||||
{
|
{
|
||||||
|
if (year < 1582) {
|
||||||
|
if (year < 0) year++;
|
||||||
|
return (year % 4) == 0;
|
||||||
|
}
|
||||||
return year % 400 == 0 || year % 4 == 0 && year % 100 != 0;
|
return year % 400 == 0 || year % 4 == 0 && year % 100 != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,13 +370,7 @@ BDate::DaysInYear() const
|
|||||||
int32
|
int32
|
||||||
BDate::DaysInMonth() const
|
BDate::DaysInMonth() const
|
||||||
{
|
{
|
||||||
if (fMonth == 2 && IsLeapYear(fYear))
|
return _DaysInMonth(fYear, fMonth);
|
||||||
return 29;
|
|
||||||
|
|
||||||
const int32 daysInMonth[12] =
|
|
||||||
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
||||||
|
|
||||||
return daysInMonth[fMonth -1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -465,7 +442,153 @@ BDate::LongMonthName(int32 month) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
int32
|
||||||
|
BDate::DateToJulianDay() const
|
||||||
|
{
|
||||||
|
return _DateToJulianDay(fYear, fMonth, fDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDate::operator!=(const BDate& date) const
|
||||||
|
{
|
||||||
|
return DateToJulianDay() != date.DateToJulianDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDate::operator==(const BDate& date) const
|
||||||
|
{
|
||||||
|
return DateToJulianDay() == date.DateToJulianDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDate::operator<(const BDate& date) const
|
||||||
|
{
|
||||||
|
return DateToJulianDay() < date.DateToJulianDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDate::operator<=(const BDate& date) const
|
||||||
|
{
|
||||||
|
return DateToJulianDay() <= date.DateToJulianDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDate::operator>(const BDate& date) const
|
||||||
|
{
|
||||||
|
return DateToJulianDay() > date.DateToJulianDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDate::operator>=(const BDate& date) const
|
||||||
|
{
|
||||||
|
return DateToJulianDay() >= date.DateToJulianDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDate::_SetDate(int32 year, int32 month, int32 day)
|
||||||
|
{
|
||||||
|
fDay = -1;
|
||||||
|
fYear = -1;
|
||||||
|
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) const
|
||||||
|
{
|
||||||
|
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) const
|
||||||
|
{
|
||||||
|
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 -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BDateTime
|
||||||
|
|
||||||
|
|
||||||
BDateTime::BDateTime(const BDate &date, const BTime &time)
|
BDateTime::BDateTime(const BDate &date, const BTime &time)
|
||||||
|
|||||||
Reference in New Issue
Block a user