Fix the gregorian date <-> julian day calculations in QDate
authorJon Severinsson <jon@severinsson.net>
Mon, 8 Oct 2012 04:46:28 +0000 (06:46 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Fri, 2 Nov 2012 11:16:49 +0000 (12:16 +0100)
commit53e6cb3ff676f91a51d55e5740c7174f0c15e390
tree22f10a63b714f0a0d9f49071916ab5d4f7f6963b
parentf01b498310ea7c05ec73669b34cb83b9f159006f
Fix the gregorian date <-> julian day calculations in QDate

The old code is just plain wrong for negative julian days. Replaced
with plain math from The Calendar FAQ [1], which is correct for all
julian days, provided you use mathematical integer division (round to
negative infinity) rather than c++11 integer division (round to zero).

[1] http://www.tondering.dk/claus/cal/julperiod.php

While the conversion code works for up to around JD +/- (2^63/4), we
only use an int for the year in the API, so this patch limits minJd()
and maxJd() to 1 Jan (2^31) BC and 31 Dec (2^31-1) AD, respectively.

Note that while the new conversion code looks like it would be more
expensive than the old, gcc will in fact be able to optimize it to be
slightly faster (probably because x86 hardware implements round to
negative infinity, and so GCC manages to optimize floordiv to a single
instruction, compared to the three instuctions needed for operator/).

In the following test application, run with a release mode Qt and
redirecting stderr to /dev/null, I measured an improvement from
6.81s +/- 0.08s to 6.26s +/- 0.16s user time over five runs on an
otherwise idle x86_64 system.

int main(int, char *[])
{
    int year, month, day;
    qint64 jd;
    for (qint64 i = Q_INT64_C(-1048576) ; i < Q_INT64_C(1048576); ++i) {
        QDate::fromJulianDay(i).getDate(&year, &month, &day);
        jd = QDate(year, month, day).toJulianDay();
        qDebug() << jd << year << month << day;
    }
}

Change-Id: Ifd0dd01f0027f260401f7f9b4f1201d2b7a3b087
Reviewed-by: David Faure (KDE) <faure@kde.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/corelib/tools/qdatetime.cpp
src/corelib/tools/qdatetime.h
tests/auto/corelib/tools/qdate/tst_qdate.cpp