diff options
author | John Layt <jlayt@kde.org> | 2012-01-09 20:50:00 +0000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-02-05 00:26:07 +0100 |
commit | fc24979e43162b27b7a482fd4963ae615f5ce54f (patch) | |
tree | f216b4a995e674ec02982f91ced977f60d5cbdab /src | |
parent | 8327fa7c11f6c84ccc66be4365ee282a76288788 (diff) |
QDateTime: Remove Julian Calendar
Convert QDate to only use Gregorian calendar and not Julian calendar
before 1582. In future the Julian can be used via proper calendar
classes.
Change-Id: I547a3550332057a0ab1be616706630b6afaceffc
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/tools/qdatetime.cpp | 165 |
1 files changed, 36 insertions, 129 deletions
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index e05eb371dd..8649690c72 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -82,7 +82,7 @@ enum { MSECS_PER_HOUR = 3600000, SECS_PER_MIN = 60, MSECS_PER_MIN = 60000, - JULIAN_DAY_FOR_EPOCH = 2440588 // result of julianDayFromGregorianDate(1970, 1, 1) + JULIAN_DAY_FOR_EPOCH = 2440588 // result of julianDayFromDate(1970, 1, 1) }; static inline QDate fixedDate(int y, int m, int d) @@ -92,66 +92,41 @@ static inline QDate fixedDate(int y, int m, int d) return result; } -static inline qint64 julianDayFromGregorianDate(qint64 year, int month, int day) +static inline qint64 julianDayFromDate(qint64 year, int month, int day) { - // Gregorian calendar starting from October 15, 1582 + // Gregorian calendar // Algorithm from Henry F. Fliegel and Thomas C. Van Flandern + + if (year < 0) + ++year; + return (1461 * (year + 4800 + (month - 14) / 12)) / 4 + (367 * (month - 2 - 12 * ((month - 14) / 12))) / 12 - (3 * ((year + 4900 + (month - 14) / 12) / 100)) / 4 + day - 32075; } -static qint64 julianDayFromDate(qint64 year, int month, int day) -{ - if (year > 1582 || (year == 1582 && (month > 10 || (month == 10 && day >= 15)))) { - return julianDayFromGregorianDate(year, month, day); - } else if (year < 1582 || (year == 1582 && (month < 10 || (month == 10 && day <= 4)))) { - // Julian calendar until October 4, 1582 - // Algorithm from Frequently Asked Questions about Calendars by Claus Toendering - if (year < 0) - ++year; - int a = (14 - month) / 12; - return (153 * (month + (12 * a) - 3) + 2) / 5 - + (1461 * (year + 4800 - a)) / 4 - + day - 32083; - } else { - // the day following October 4, 1582 is October 15, 1582 - return std::numeric_limits<qint64>::min(); // i.e. nullJd() - } -} - static void getDateFromJulianDay(qint64 julianDay, int *year, int *month, int *day) { int y, m, d; - if (julianDay >= 2299161) { - // Gregorian calendar starting from October 15, 1582 - // This algorithm is from Henry F. Fliegel and Thomas C. Van Flandern - qint64 ell, n, i, j; //TODO These will need to be bigger to prevent overflow!!! - ell = julianDay + 68569; - n = (4 * ell) / 146097; - ell = ell - (146097 * n + 3) / 4; - i = (4000 * (ell + 1)) / 1461001; - ell = ell - (1461 * i) / 4 + 31; - j = (80 * ell) / 2447; - d = ell - (2447 * j) / 80; - ell = j / 11; - m = j + 2 - (12 * ell); - y = 100 * (n - 49) + i + ell; - } else { - // Julian calendar until October 4, 1582 - // Algorithm from Frequently Asked Questions about Calendars by Claus Toendering - julianDay += 32082; - qint64 dd = (4 * julianDay + 3) / 1461; //TODO These may need to be bigger to prevent overflow!!! - qint64 ee = julianDay - (1461 * dd) / 4; //TODO These may need to be bigger to prevent overflow!!! - qint64 mm = ((5 * ee) + 2) / 153; //TODO These may need to be bigger to prevent overflow!!! - d = ee - (153 * mm + 2) / 5 + 1; - m = mm + 3 - 12 * (mm / 10); - y = dd - 4800 + (mm / 10); - if (y <= 0) - --y; - } + // Gregorian calendar + // This algorithm is from Henry F. Fliegel and Thomas C. Van Flandern + qint64 ell, n, i, j; //TODO These will need to be bigger to prevent overflow!!! + ell = julianDay + 68569; + n = (4 * ell) / 146097; + ell = ell - (146097 * n + 3) / 4; + i = (4000 * (ell + 1)) / 1461001; + ell = ell - (1461 * i) / 4 + 31; + j = (80 * ell) / 2447; + d = ell - (2447 * j) / 80; + ell = j / 11; + m = j + 2 - (12 * ell); + y = 100 * (n - 49) + i + ell; + + if (y<= 0) + --y; + if (year) *year = y; if (month) @@ -197,12 +172,10 @@ static QString fmtDateTime(const QString& f, const QTime* dt = 0, const QDate* d A QDate object contains a calendar date, i.e. year, month, and day - numbers, in the Gregorian calendar. (see \l{QDate G and J} {Use of - Gregorian and Julian Calendars} for dates prior to 15 October - 1582). It can read the current date from the system clock. It - provides functions for comparing dates, and for manipulating - dates. For example, it is possible to add and subtract days, - months, and years to dates. + numbers, in the Gregorian calendar. It can read the current date + from the system clock. It provides functions for comparing dates, + and for manipulating dates. For example, it is possible to add + and subtract days, months, and years to dates. A QDate object is typically created either by giving the year, month, and day numbers explicitly. Note that QDate interprets two @@ -233,26 +206,6 @@ static QString fmtDateTime(const QString& f, const QTime* dt = 0, const QDate* d \section1 - \target QDate G and J - \section2 Use of Gregorian and Julian Calendars - - QDate uses the Gregorian calendar in all locales, beginning - on the date 15 October 1582. For dates up to and including 4 - October 1582, the Julian calendar is used. This means there is a - 10-day gap in the internal calendar between the 4th and the 15th - of October 1582. When you use QDateTime for dates in that epoch, - the day after 4 October 1582 is 15 October 1582, and the dates in - the gap are invalid. - - The Julian to Gregorian changeover date used here is the date when - the Gregorian calendar was first introduced, by Pope Gregory - XIII. That change was not universally accepted and some localities - only executed it at a later date (if at all). QDateTime - doesn't take any of these historical facts into account. If an - application must support a locale-specific dating system, it must - do so on its own, remembering to convert the dates using the - Julian day. - \section2 No Year 0 There is no year 0. Dates in that year are considered invalid. The @@ -985,11 +938,6 @@ QDate QDate::addDays(qint64 ndays) const resulting month/year, this function will return a date that is the latest valid date. - \warning QDate has a date hole around the days introducing the - Gregorian calendar (the days 5 to 14 October 1582, inclusive, do - not exist). If the calculation ends in one of those days, QDate - will return either October 4 or October 15. - \sa addDays() addYears() */ @@ -1039,10 +987,6 @@ QDate QDate::addMonths(int nmonths) const // yes, adjust the date by +1 or -1 years y += increasing ? +1 : -1; - // did we end up in the Gregorian/Julian conversion hole? - if (y == 1582 && m == 10 && d > 4 && d < 15) - d = increasing ? 15 : 4; - return fixedDate(y, m, d); } @@ -1332,14 +1276,10 @@ QDate QDate::fromString(const QString &string, const QString &format) bool QDate::isValid(int year, int month, int day) { - // there is no year 0 in the Julian calendar + // there is no year 0 in the Gregorian calendar if (year == 0) return false; - // passage from Julian to Gregorian calendar - if (year == 1582 && month == 10 && day > 4 && day < 15) - return false; - return (day > 0 && month > 0 && month <= 12) && (day <= monthDays[month] || (day == 29 && month == 2 && isLeapYear(year))); } @@ -1353,14 +1293,11 @@ bool QDate::isValid(int year, int month, int day) bool QDate::isLeapYear(int y) { - if (y < 1582) { - if ( y < 1) { // No year 0 in Julian calendar, so -1, -5, -9 etc are leap years - ++y; - } - return y % 4 == 0; - } else { - return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0; - } + // No year 0 in Gregorian calendar, so -1, -5, -9 etc are leap years + if ( y < 1) + ++y; + + return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0; } /*! \fn static QDate QDate::fromJulianDay(int jd) @@ -2088,26 +2025,6 @@ int QTime::elapsed() const \section1 - \target QDateTime G and J - \section2 Use of Gregorian and Julian Calendars - - QDate uses the Gregorian calendar in all locales, beginning - on the date 15 October 1582. For dates up to and including 4 - October 1582, the Julian calendar is used. This means there is a - 10-day gap in the internal calendar between the 4th and the 15th - of October 1582. When you use QDateTime for dates in that epoch, - the day after 4 October 1582 is 15 October 1582, and the dates in - the gap are invalid. - - The Julian to Gregorian changeover date used here is the date when - the Gregorian calendar was first introduced, by Pope Gregory - XIII. That change was not universally accepted and some localities - only executed it at a later date (if at all). QDateTime - doesn't take any of these historical facts into account. If an - application must support a locale-specific dating system, it must - do so on its own, remembering to convert the dates using the - Julian day. - \section2 No Year 0 There is no year 0. Dates in that year are considered invalid. The @@ -2134,16 +2051,6 @@ int QTime::elapsed() const shortcomings in the available conversion formulas. Conversions outside this range are not guaranteed to be correct. This may change in the future. - The Gregorian calendar was introduced in different places around - the world on different dates. QDateTime uses QDate to store the - date, so it uses the Gregorian calendar for all locales, beginning - on the date 15 October 1582. For dates up to and including 4 - October 1582, QDateTime uses the Julian calendar. This means - there is a 10-day gap in the QDateTime calendar between the 4th - and the 15th of October 1582. When you use QDateTime for dates in - that epoch, the day after 4 October 1582 is 15 October 1582, and - the dates in the gap are invalid. - \section2 Use of System Timezone @@ -3052,8 +2959,8 @@ qint64 QDateTime::currentMSecsSinceEpoch() GetSystemTime(&st); return msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds) + - qint64(julianDayFromGregorianDate(st.wYear, st.wMonth, st.wDay) - - julianDayFromGregorianDate(1970, 1, 1)) * Q_INT64_C(86400000); + qint64(julianDayFromDate(st.wYear, st.wMonth, st.wDay) + - julianDayFromDate(1970, 1, 1)) * Q_INT64_C(86400000); } #elif defined(Q_OS_UNIX) |