[Development] QtCS - QDateTime changes

John Layt jlayt at kde.org
Tue Aug 6 23:44:24 CEST 2013


On Monday 05 Aug 2013 08:32:00 Knoll Lars wrote:
> On 26.07.13 22:26, "John Layt" <jlayt at kde.org> wrote:

> >It has been discussed to re-write QDateTime to internally store as an
> >absolute msecs since epoch which would inherently fix these issues and
> >greatly simplify the maths and conversion code, but this would
> >radically change the behaviour of QDateTime which currently treats the
> >ymd/hms values as ³fixed² and the time spec is used to interpret that
> >value. This would mostly affect the default Qt::LocalTime spec where
> >the system time zone can change underneath QDateTime causing the
> >absolute UTC value to change. There is also the behaviour that you can
> >store an invalid date but valid time in QDateTime, and later fix the
> >date to be valid.  Considerable special case code could be required to
> >keep consistent with the current behaviour.
> 
> If we'd write this class now, storing the date time as ms since epoch is
> what I'd prefer. It would be nice if we can change to that. Maybe it could
> work if you in addition have two boolean flags indicating invalid dates
> and times.

OK, I've had a re-think, and I think I now have a plan to do this cleanly with 
no regressions that I'll try this weekend.  I'm not sure how much I can break 
it up into small parts though, it may be one big commit.

I was thinking that LocalTime could always be stored as if it was UTC, i.e. 
without actally converting it first, allowing us to always know the exact 
date/time value that it represents without worrying what the system tz says or 
if it changes.  We'd still validate at init, and convert to UTC proper when 
doing date maths and Spec conversions  Time maths won't need conversion.  This 
has the advantage of not calling mktime every time just to retrieve the 
date/time values, we just use the short UTC formula like the other Specs.  If 
the system tz does change we don't mind, we still have the original values and 
just revalidate them against the new tz.  All other TimeSpec's will be stored 
in "real" UTC msecs.

This means QDateTimePrivate will store the following data:

qint64 m_msecsSinceEpoch;           // Replaces QDate/QTime
Qt::TimeSpec m_spec;                // replaces QDateTimePrivate::TimeSpec
QDateTimePrivate::Status m_status;  // New, see below
int m_offsetFromUtc;

So effectively no change in the memory used, the int saved from QTime gets used 
for the Status enum.

The new private Status enum will have values like:

InvalidDateTime
InvalidDate
InvalidTime
FirstOccurrence
SecondOccurrence

Invalid dates/times will be encoded as UTC dates/times and the Status used to 
interpret them, i.e. ignore the bit that's invalid.

We will have to keep the old QDateTimePrivate::TimeSpec defined for back-wards 
compatible serialise/de-serialise, but we'll calculate it on the fly.

I could split the change to TimeSpec and Status out as a spearate commit from 
the change to msecs, but I'm not sure how much sense that would make as some 
bits would be broken in the interim.

> I don't think the corner cases where the time zone changes while the Qt
> app is running is a problem. I would actually expect that having QDT
> stored as ms since epoch would fix bugs here in 90% of the cases.

I was more concerned about the serialise/de-serialise scenario where the local 
values written out must be read back the same regardless of the tz, but using 
my solution above would cover this.

> >* Would reduce the historic supported date range, but QDateTime is
> >only promised to be useful from 1970 onwards anyway
> 
> Why? The int64 should be plenty to store all historic dates.

QDate currently is a qint64 for storing Julian Days on it's own, so a range of 
about +/- 2 billion years.  Using a qint64 for msecs will lose some of 
that extreme date range, allowing "only" about +/- 292 million years :-)

The 1970 documented useful range is because LocalTime uses POSIX utilities 
that only take a time_t, i.e. a uint allowing 1970 to 2037, and fudges dates 
outside that range using adjustDate().  The docs say we don't apply Daylight 
Time outside the range, but that's not actually what the code does, it adjusts 
the year number to be 1970 or 2037 so effectively applies the rule from that 
year, but not very accurately.  I'll fix that.  For QTimeZone we won't have 
this issue, the code properly calculates before 1970 and after 2037 using an 
appropriate rule from the system database.

Cheers!

John.




More information about the Development mailing list