summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dist/changes-5.0.04
-rw-r--r--src/corelib/tools/qdatetime.cpp165
-rw-r--r--tests/auto/corelib/tools/qdate/tst_qdate.cpp65
-rw-r--r--tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp8
4 files changed, 62 insertions, 180 deletions
diff --git a/dist/changes-5.0.0 b/dist/changes-5.0.0
index ed5ddc240d..e5f57732ba 100644
--- a/dist/changes-5.0.0
+++ b/dist/changes-5.0.0
@@ -241,6 +241,10 @@ QtCore
in Qt 4 they returned a null QString or a null QStringRef.
* QDate, QTime, and QDateTime have undergone important behavioural changes:
+ * QDate only implements the Gregorian calendar, the switch to the Julian
+ calendar before 1582 has been removed. This means all QDate methods will
+ return different results for dates prior to 15 October 1582, and there is
+ no longer a gap between 4 October 1582 and 15 October 1582.
* QDate::setYMD() is deprecated, use QDate::setDate() instead
* Most methods now apply strict validity checks and will return appropriate
and consistent values when invalid. For example, QDate::year() will return
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)
diff --git a/tests/auto/corelib/tools/qdate/tst_qdate.cpp b/tests/auto/corelib/tools/qdate/tst_qdate.cpp
index 4ce2a51902..4921a7e734 100644
--- a/tests/auto/corelib/tools/qdate/tst_qdate.cpp
+++ b/tests/auto/corelib/tools/qdate/tst_qdate.cpp
@@ -185,10 +185,10 @@ void tst_QDate::isValid_data()
QTest::newRow("idec") << 2000 << 12 << 32 << nullJd << false;
// the beginning of the Julian Day calendar:
- QTest::newRow("jd earliest formula") << -4800 << 1 << 1 << qint64( -31776) << true;
- QTest::newRow("jd -1") << -4714 << 12 << 31 << qint64( -1) << true;
- QTest::newRow("jd 0") << -4713 << 1 << 1 << qint64( 0) << true;
- QTest::newRow("jd 1") << -4713 << 1 << 2 << qint64( 1) << true;
+ QTest::newRow("jd earliest formula") << -4800 << 1 << 1 << qint64( -31738) << true;
+ QTest::newRow("jd -1") << -4714 << 11 << 23 << qint64( -1) << true;
+ QTest::newRow("jd 0") << -4714 << 11 << 24 << qint64( 0) << true;
+ QTest::newRow("jd 1") << -4714 << 11 << 25 << qint64( 1) << true;
QTest::newRow("jd latest formula") << 1400000 << 12 << 31 << qint64(513060925) << true;
}
@@ -259,19 +259,14 @@ void tst_QDate::dayOfWeek_data()
QTest::newRow("data5") << 2000 << 1 << 7 << 5;
QTest::newRow("data6") << 2000 << 1 << 8 << 6;
QTest::newRow("data7") << 2000 << 1 << 9 << 7;
- QTest::newRow("data8") << 1815 << 6 << 15 << 4;
- QTest::newRow("data9") << 1815 << 6 << 15 << 4;
- QTest::newRow("data10") << 1500 << 1 << 1 << 3;
- QTest::newRow("data11") << -1500 << 1 << 1 << 7;
- QTest::newRow("data12") << -4800 << 1 << 1 << 5;
- QTest::newRow("data13") << -4800 << 1 << 4 << 1;
- QTest::newRow("data14") << -4800 << 1 << 5 << 2;
- QTest::newRow("data15") << -4800 << 1 << 6 << 3;
- QTest::newRow("data16") << -4800 << 1 << 7 << 4;
- QTest::newRow("data17") << -4800 << 1 << 8 << 5;
- QTest::newRow("data18") << -4800 << 1 << 9 << 6;
- QTest::newRow("data19") << -4800 << 1 << 10 << 7;
- QTest::newRow("data20") << -4800 << 1 << 11 << 1;
+ QTest::newRow("data8") << -4800 << 1 << 1 << 1;
+ QTest::newRow("data9") << -4800 << 1 << 2 << 2;
+ QTest::newRow("data10") << -4800 << 1 << 3 << 3;
+ QTest::newRow("data12") << -4800 << 1 << 4 << 4;
+ QTest::newRow("data12") << -4800 << 1 << 5 << 5;
+ QTest::newRow("data13") << -4800 << 1 << 6 << 6;
+ QTest::newRow("data14") << -4800 << 1 << 7 << 7;
+ QTest::newRow("data15") << -4800 << 1 << 8 << 1;
}
void tst_QDate::dayOfWeek()
@@ -300,9 +295,9 @@ void tst_QDate::dayOfYear_data()
QTest::newRow("data5") << 2001 << 12 << 31 << 365;
QTest::newRow("data6") << 1815 << 1 << 1 << 1;
QTest::newRow("data7") << 1815 << 12 << 31 << 365;
- QTest::newRow("data8") << 1582 << 1 << 1 << 1;
- QTest::newRow("data9") << 1582 << 12 << 31 << 355;
- QTest::newRow("data10") << 1500 << 1 << 1 << 1;
+ QTest::newRow("data8") << 1500 << 1 << 1 << 1;
+ QTest::newRow("data9") << 1500 << 12 << 31 << 365;
+ QTest::newRow("data10") << -1500 << 1 << 1 << 1;
QTest::newRow("data11") << -1500 << 12 << 31 << 365;
QTest::newRow("data12") << -4800 << 1 << 1 << 1;
QTest::newRow("data13") << -4800 << 12 << 31 << 365;
@@ -589,14 +584,6 @@ void tst_QDate::addMonths_data()
QTest::newRow( "data15" ) << 1 << 1 << 1 << -12 << -1 << 1 << 1;
QTest::newRow( "data16" ) << -1 << 12 << 1 << 1 << 1 << 1 << 1;
QTest::newRow( "data17" ) << -1 << 1 << 1 << 12 << 1 << 1 << 1;
-
- // Gregorian/Julian switchover
- QTest::newRow( "data18" ) << 1582 << 9 << 4 << 1 << 1582 << 10 << 4;
- QTest::newRow( "data19" ) << 1582 << 9 << 10 << 1 << 1582 << 10 << 15;
- QTest::newRow( "data20" ) << 1582 << 9 << 20 << 1 << 1582 << 10 << 20;
- QTest::newRow( "data21" ) << 1582 << 11 << 4 << -1 << 1582 << 10 << 4;
- QTest::newRow( "data22" ) << 1582 << 11 << 10 << -1 << 1582 << 10 << 4;
- QTest::newRow( "data23" ) << 1582 << 11 << 20 << -1 << 1582 << 10 << 20;
}
void tst_QDate::addYears()
@@ -930,10 +917,10 @@ void tst_QDate::isLeapYear()
QVERIFY(QDate::isLeapYear(4));
QVERIFY(!QDate::isLeapYear(7));
QVERIFY(QDate::isLeapYear(8));
- QVERIFY(QDate::isLeapYear(100));
+ QVERIFY(!QDate::isLeapYear(100));
QVERIFY(QDate::isLeapYear(400));
- QVERIFY(QDate::isLeapYear(700));
- QVERIFY(QDate::isLeapYear(1500));
+ QVERIFY(!QDate::isLeapYear(700));
+ QVERIFY(!QDate::isLeapYear(1500));
QVERIFY(QDate::isLeapYear(1600));
QVERIFY(!QDate::isLeapYear(1700));
QVERIFY(!QDate::isLeapYear(1800));
@@ -1184,24 +1171,16 @@ void tst_QDate::roundtrip() const
// Test Julian round trip around JD 0 and current low end of valid range
QDate testDate;
- QDate loopDate = QDate::fromJulianDay(-31776); // 1 Jan 4800 BC
- while (loopDate.toJulianDay() <= 5113) { // 31 Dec 4700 AD
+ QDate loopDate = QDate::fromJulianDay(-31738); // 1 Jan 4800 BC
+ while (loopDate.toJulianDay() <= 5150) { // 31 Dec 4700 BC
testDate.setDate(loopDate.year(), loopDate.month(), loopDate.day());
QCOMPARE(loopDate.toJulianDay(), testDate.toJulianDay());
loopDate = loopDate.addDays(1);
}
// Test Julian round trip in both BC and AD
- loopDate = QDate::fromJulianDay(1684899); // 1 Jan 100 BC
- while (loopDate.toJulianDay() <= 1757948) { // 31 Dec 100 AD
- testDate.setDate(loopDate.year(), loopDate.month(), loopDate.day());
- QCOMPARE(loopDate.toJulianDay(), testDate.toJulianDay());
- loopDate = loopDate.addDays(1);
- }
-
- // Test Julian and Gregorian round trip during changeover period
- loopDate = QDate::fromJulianDay(2298153); // 1 Jan 1580 AD
- while (loopDate.toJulianDay() <= 2300334) { // 31 Dec 1585 AD
+ loopDate = QDate::fromJulianDay(1684901); // 1 Jan 100 BC
+ while (loopDate.toJulianDay() <= 1757949) { // 31 Dec 100 AD
testDate.setDate(loopDate.year(), loopDate.month(), loopDate.day());
QCOMPARE(loopDate.toJulianDay(), testDate.toJulianDay());
loopDate = loopDate.addDays(1);
diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
index 2cb3db533e..af8deefa4c 100644
--- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
@@ -726,14 +726,6 @@ void tst_QDateTime::addSecs_data()
QTest::newRow("toPositive") << QDateTime(QDate(-1, 12, 31), QTime(23, 59, 59), Qt::UTC)
<< 1
<< QDateTime(QDate(1, 1, 1), QTime(0, 0, 0), Qt::UTC);
-
- // Gregorian/Julian switchover
- QTest::newRow("toGregorian") << QDateTime(QDate(1582, 10, 4), QTime(23, 59, 59))
- << 1
- << QDateTime(QDate(1582, 10, 15), QTime(0, 0, 0));
- QTest::newRow("toJulian") << QDateTime(QDate(1582, 10, 15), QTime(0, 0, 0))
- << -1
- << QDateTime(QDate(1582, 10, 4), QTime(23, 59, 59));
}
void tst_QDateTime::addSecs()