QDateTime - Change date/time storage to msecs
Change from storing the date and time as QDate and QTime to a serialised msecs format. This format is a direct translation of the QDate and QTime values, it is not the actual msecs since the Unix epoch. This msecs format ensures we are always able to recreate the original QDate and QTime values, but should still simplify the code and improve performance. Because we no longer store the explicit date and time we need to store their isNull()/isValid() status separately. The changes in storage results in the same memory footprint as before. Note that this change does not optimize the code nor set out to fix the known bugs, it only seeks to maintain the current behavior, although some bugs are fixed implicitly. More bug fixes and optimizations will follow. [ChangeLog][Important Behavior Changes] The supported date range in QDateTime has been reduced to about +/- 292 million years, the range supported by the number of msecs since the Unix epoch of 1 Jan 1970 as stored in a qint64, and as able to be used in the setMSecsSinceEpoch() and toMSecsSinceEpoch() methods. Change-Id: I98804d8781909555d3313a3a7080eb8e70cb46ad Reviewed-by: Sérgio Martins <sergio.martins@kdab.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
662f23ff5b
commit
18322bfabc
@ -108,6 +108,7 @@ struct tm {
|
||||
#endif // _TM_DEFINED
|
||||
|
||||
FILETIME qt_wince_time_tToFt( time_t tt );
|
||||
time_t qt_wince_ftToTime_t( const FILETIME ft );
|
||||
|
||||
// File I/O ---------------------------------------------------------
|
||||
#define _O_RDONLY 0x0001
|
||||
@ -433,6 +434,7 @@ generate_inline_return_func4(getenv_s, errno_t, size_t *, char *, size_t, const
|
||||
generate_inline_return_func2(_putenv_s, errno_t, const char *, const char *)
|
||||
generate_inline_return_func0(_getpid, int)
|
||||
generate_inline_return_func1(time_tToFt, FILETIME, time_t)
|
||||
generate_inline_return_func1(ftToTime_t, time_t, FILETIME)
|
||||
generate_inline_return_func0(_getdrive, int)
|
||||
generate_inline_return_func2(_waccess, int, const wchar_t *, int)
|
||||
generate_inline_return_func3(_wopen, int, const wchar_t *, int, int)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -80,28 +80,45 @@ public:
|
||||
DaylightTime
|
||||
};
|
||||
|
||||
QDateTimePrivate() : m_spec(Qt::LocalTime), m_offsetFromUtc(0) {}
|
||||
QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec,
|
||||
int offsetSeconds);
|
||||
QDateTimePrivate(const QDateTimePrivate &other)
|
||||
: QSharedData(other), date(other.date), time(other.time), m_spec(other.m_spec),
|
||||
m_offsetFromUtc(other.m_offsetFromUtc)
|
||||
// Status of date/time
|
||||
enum StatusFlag {
|
||||
NullDate = 0x01,
|
||||
NullTime = 0x02,
|
||||
ValidDate = 0x04,
|
||||
ValidTime = 0x08,
|
||||
};
|
||||
Q_DECLARE_FLAGS(StatusFlags, StatusFlag)
|
||||
|
||||
QDateTimePrivate() : m_msecs(0),
|
||||
m_spec(Qt::LocalTime),
|
||||
m_offsetFromUtc(0),
|
||||
m_status(NullDate | NullTime)
|
||||
{}
|
||||
|
||||
QDate date;
|
||||
QTime time;
|
||||
QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec,
|
||||
int offsetSeconds);
|
||||
|
||||
QDateTimePrivate(const QDateTimePrivate &other) : QSharedData(other),
|
||||
m_msecs(other.m_msecs),
|
||||
m_spec(other.m_spec),
|
||||
m_offsetFromUtc(other.m_offsetFromUtc),
|
||||
m_status(other.m_status)
|
||||
{}
|
||||
|
||||
qint64 m_msecs;
|
||||
Qt::TimeSpec m_spec;
|
||||
int m_offsetFromUtc;
|
||||
|
||||
// Get current date/time in LocalTime and put result in outDate and outTime
|
||||
Spec getLocal(QDate &outDate, QTime &outTime) const;
|
||||
// Get current date/time in UTC and put result in outDate and outTime
|
||||
void getUTC(QDate &outDate, QTime &outTime) const;
|
||||
|
||||
// Add msecs to given datetime and put result in utcDate and utcTime
|
||||
static void addMSecs(QDate &utcDate, QTime &utcTime, qint64 msecs);
|
||||
StatusFlags m_status;
|
||||
|
||||
void setTimeSpec(Qt::TimeSpec spec, int offsetSeconds);
|
||||
void setDateTime(const QDate &date, const QTime &time);
|
||||
void getDateTime(QDate *date, QTime *time) const;
|
||||
|
||||
// Get/set date and time status
|
||||
inline bool isNullDate() const { return (m_status & NullDate) == NullDate; }
|
||||
inline bool isNullTime() const { return (m_status & NullTime) == NullTime; }
|
||||
inline bool isValidDate() const { return (m_status & ValidDate) == ValidDate; }
|
||||
inline bool isValidTime() const { return (m_status & ValidTime) == ValidTime; }
|
||||
|
||||
static inline qint64 minJd() { return QDate::minJd(); }
|
||||
static inline qint64 maxJd() { return QDate::maxJd(); }
|
||||
|
@ -528,12 +528,7 @@ void tst_QDateTime::setMSecsSinceEpoch_data()
|
||||
// positive value 1 too big for qint64max, causing an overflow.
|
||||
<< std::numeric_limits<qint64>::min() + 1
|
||||
<< QDateTime(QDate(-292275056, 5, 16), QTime(16, 47, 4, 193), Qt::UTC)
|
||||
#ifdef Q_OS_WIN
|
||||
// Windows applies Daylight Time to dates before 1980, Olsen does not
|
||||
<< QDateTime(QDate(-292275056, 5, 16), QTime(18, 47, 4, 193), Qt::LocalTime);
|
||||
#else
|
||||
<< QDateTime(QDate(-292275056, 5, 16), QTime(17, 47, 4, 193), Qt::LocalTime);
|
||||
#endif
|
||||
QTest::newRow("max")
|
||||
<< std::numeric_limits<qint64>::max()
|
||||
<< QDateTime(QDate(292278994, 8, 17), QTime(7, 12, 55, 807), Qt::UTC)
|
||||
@ -561,7 +556,9 @@ void tst_QDateTime::setMSecsSinceEpoch()
|
||||
localDt.setTimeSpec(Qt::LocalTime);
|
||||
localDt.setMSecsSinceEpoch(msecs);
|
||||
|
||||
QCOMPARE(localDt, utc);
|
||||
// LocalTime will overflow for max
|
||||
if (msecs != std::numeric_limits<qint64>::max())
|
||||
QCOMPARE(localDt, utc);
|
||||
QCOMPARE(localDt.timeSpec(), Qt::LocalTime);
|
||||
}
|
||||
|
||||
@ -590,7 +587,9 @@ void tst_QDateTime::fromMSecsSinceEpoch()
|
||||
QDateTime dtUtc = QDateTime::fromMSecsSinceEpoch(msecs, Qt::UTC);
|
||||
QDateTime dtOffset = QDateTime::fromMSecsSinceEpoch(msecs, Qt::OffsetFromUTC, 60*60);
|
||||
|
||||
QCOMPARE(dtLocal, utc);
|
||||
// LocalTime will overflow for max
|
||||
if (msecs != std::numeric_limits<qint64>::max())
|
||||
QCOMPARE(dtLocal, utc);
|
||||
|
||||
QCOMPARE(dtUtc, utc);
|
||||
QCOMPARE(dtUtc.date(), utc.date());
|
||||
@ -598,7 +597,9 @@ void tst_QDateTime::fromMSecsSinceEpoch()
|
||||
|
||||
QCOMPARE(dtOffset, utc);
|
||||
QCOMPARE(dtOffset.offsetFromUtc(), 60*60);
|
||||
QCOMPARE(dtOffset.time(), utc.time().addMSecs(60*60*1000));
|
||||
// // OffsetFromUTC will overflow for max
|
||||
if (msecs != std::numeric_limits<qint64>::max())
|
||||
QCOMPARE(dtOffset.time(), utc.time().addMSecs(60*60*1000));
|
||||
|
||||
if (europeanTimeZone) {
|
||||
QCOMPARE(dtLocal.toLocalTime(), european);
|
||||
@ -608,7 +609,9 @@ void tst_QDateTime::fromMSecsSinceEpoch()
|
||||
QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo");
|
||||
}
|
||||
|
||||
QCOMPARE(dtLocal.toMSecsSinceEpoch(), msecs);
|
||||
// LocalTime will overflow for max
|
||||
if (msecs != std::numeric_limits<qint64>::max())
|
||||
QCOMPARE(dtLocal.toMSecsSinceEpoch(), msecs);
|
||||
QCOMPARE(dtUtc.toMSecsSinceEpoch(), msecs);
|
||||
QCOMPARE(dtOffset.toMSecsSinceEpoch(), msecs);
|
||||
|
||||
@ -619,7 +622,9 @@ void tst_QDateTime::fromMSecsSinceEpoch()
|
||||
}
|
||||
|
||||
QDateTime reference(QDate(1970, 1, 1), QTime(), Qt::UTC);
|
||||
QCOMPARE(dtLocal, reference.addMSecs(msecs));
|
||||
// LocalTime will overflow for max
|
||||
if (msecs != std::numeric_limits<qint64>::max())
|
||||
QCOMPARE(dtLocal, reference.addMSecs(msecs));
|
||||
QCOMPARE(dtUtc, reference.addMSecs(msecs));
|
||||
QCOMPARE(dtOffset, reference.addMSecs(msecs));
|
||||
}
|
||||
@ -982,15 +987,8 @@ void tst_QDateTime::addSecs_data()
|
||||
<< QDateTime(QDate(2005, 1, 1), standardTime, Qt::LocalTime);
|
||||
QTest::newRow("cet3") << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << 86400
|
||||
<< QDateTime(QDate(1760, 1, 2), standardTime, Qt::LocalTime);
|
||||
#ifdef Q_OS_WIN
|
||||
// QDateTime uses 1980 on Windows, which did have daylight savings in July
|
||||
QTest::newRow("cet4") << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << (86400 * 185)
|
||||
<< QDateTime(QDate(1760, 7, 4), daylightTime, Qt::LocalTime);
|
||||
#else
|
||||
// QDateTime uses 1970 everywhere else, which did NOT have daylight savings in July
|
||||
QTest::newRow("cet4") << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << (86400 * 185)
|
||||
<< QDateTime(QDate(1760, 7, 4), standardTime, Qt::LocalTime);
|
||||
#endif
|
||||
QTest::newRow("cet5") << QDateTime(QDate(1760, 1, 1), standardTime, Qt::LocalTime) << (86400 * 366)
|
||||
<< QDateTime(QDate(1761, 1, 1), standardTime, Qt::LocalTime);
|
||||
QTest::newRow("cet6") << QDateTime(QDate(4000, 1, 1), standardTime, Qt::LocalTime) << 86400
|
||||
@ -1088,33 +1086,16 @@ void tst_QDateTime::toTimeSpec_data()
|
||||
|
||||
QTest::newRow("-271821/4/20 00:00 UTC (JavaScript min date, start of day)")
|
||||
<< QDateTime(QDate(-271821, 4, 20), QTime(0, 0, 0), Qt::UTC)
|
||||
#ifdef Q_OS_WIN
|
||||
// Windows applies Daylight Time to dates before 1980, Olsen does not
|
||||
<< QDateTime(QDate(-271821, 4, 20), QTime(2, 0, 0), Qt::LocalTime);
|
||||
#else
|
||||
<< QDateTime(QDate(-271821, 4, 20), QTime(1, 0, 0), Qt::LocalTime);
|
||||
#endif
|
||||
QTest::newRow("-271821/4/20 23:00 UTC (JavaScript min date, end of day)")
|
||||
<< QDateTime(QDate(-271821, 4, 20), QTime(23, 0, 0), Qt::UTC)
|
||||
#ifdef Q_OS_WIN
|
||||
// Windows applies Daylight Time to dates before 1980, Olsen does not
|
||||
<< QDateTime(QDate(-271821, 4, 21), QTime(1, 0, 0), Qt::LocalTime);
|
||||
#else
|
||||
<< QDateTime(QDate(-271821, 4, 21), QTime(0, 0, 0), Qt::LocalTime);
|
||||
#endif
|
||||
|
||||
if (europeanTimeZone) {
|
||||
QTest::newRow("summer1") << QDateTime(QDate(2004, 6, 30), utcTime, Qt::UTC)
|
||||
<< QDateTime(QDate(2004, 6, 30), localDaylightTime, Qt::LocalTime);
|
||||
#ifdef Q_OS_WIN
|
||||
// QDateTime uses 1980 on Windows, which did have daylight savings in July
|
||||
QTest::newRow("summer2") << QDateTime(QDate(1760, 6, 30), utcTime, Qt::UTC)
|
||||
<< QDateTime(QDate(1760, 6, 30), localDaylightTime, Qt::LocalTime);
|
||||
#else
|
||||
// QDateTime uses 1970 everywhere else, which did NOT have daylight savings in July
|
||||
QTest::newRow("summer2") << QDateTime(QDate(1760, 6, 30), utcTime, Qt::UTC)
|
||||
<< QDateTime(QDate(1760, 6, 30), localStandardTime, Qt::LocalTime);
|
||||
#endif
|
||||
QTest::newRow("summer3") << QDateTime(QDate(4000, 6, 30), utcTime, Qt::UTC)
|
||||
<< QDateTime(QDate(4000, 6, 30), localDaylightTime, Qt::LocalTime);
|
||||
|
||||
@ -2437,6 +2418,7 @@ void tst_QDateTime::daylightTransitions() const
|
||||
QCOMPARE(test.time(), QTime(3, 0, 0));
|
||||
QCOMPARE(test.toMSecsSinceEpoch(), daylight2012);
|
||||
|
||||
|
||||
// Test for correct behviour for DaylightTime -> StandardTime transition, i.e. second occurrence
|
||||
|
||||
// Test setting date and time in first and second occurrence will be valid
|
||||
|
Loading…
Reference in New Issue
Block a user