Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 2

Qt-interest Archive, April 2008
QDateTime utc / localtime differs from gmtime / localtime


Message 1 in thread

I'm on a linux x86_64 box, using Qt4.3.2 - struggling with timestamps.

I have the following code:

   long l = -710996400;
   const time_t * t_t = &l;
   char * res = ctime (t_t);
   qDebug ("Res val: %s", res);

   struct tm tmp;
   gmtime_r (t_t, &tmp);
   qDebug ("y: %i, m: %i, d: %i, h: %i, mm: %i, wt: %i", tmp.tm_year, tmp.tm_mon, tmp.tm_mday, tmp.tm_hour, tmp.tm_min, tmp.tm_wday);
   QDateTime tdt (QDate (1900 + tmp.tm_year, 1 + tmp.tm_mon, tmp.tm_mday), QTime (tmp.tm_hour, tmp.tm_min, tmp.tm_sec), Qt::UTC);
   qDebug ("tdt: %s, local: %s", qPrintable (tdt.toString ()), qPrintable (tdt.toLocalTime ().toString ()));

   struct tm tmp2;
   localtime_r (t_t, &tmp2);
   qDebug ("y: %i, m: %i, d: %i, h: %i, mm: %i, wt: %i", tmp2.tm_year, tmp2.tm_mon, tmp2.tm_mday, tmp2.tm_hour, tmp2.tm_min, tmp2.tm_wday);
   QDateTime tdt2 (QDate (1900 + tmp2.tm_year, 1 + tmp2.tm_mon, tmp2.tm_mday), QTime (tmp2.tm_hour, tmp2.tm_min, tmp2.tm_sec), Qt::UTC);
   qDebug ("tdt2: %s", qPrintable (tdt2.toString ()));

and this is the output:

Res val: Sun Jun 22 00:00:00 1947
y: 47, m: 5, d: 21, h: 21, mm: 0, wt: 6
tdt: Sat Jun 21 21:00:00 1947, local: Sat Jun 21 22:00:00 1947
y: 47, m: 5, d: 22, h: 0, mm: 0, wt: 0
tdt2: Sun Jun 22 00:00:00 1947

I would have expected QDateTime::toUTC and QDateTime::toLocalTime to return the same time diff as gmtime / localtime

Is this a bug - or where does this discrepancy come from?

Frank

--
 [ signature omitted ] 

Message 2 in thread

Silly Question One: What is the timezone setting on your machine ?
Silly Question Two: Is there a reason you are messing about back in  
1947 ?

On Apr 4, 2008, at 8:26 PM, Frank Hemer wrote:
> I'm on a linux x86_64 box, using Qt4.3.2 - struggling with timestamps.
>
> I have the following code:
>
>    long l = -710996400;
>    const time_t * t_t = &l;
>    char * res = ctime (t_t);
>    qDebug ("Res val: %s", res);
>
>    struct tm tmp;
>    gmtime_r (t_t, &tmp);
>    qDebug ("y: %i, m: %i, d: %i, h: %i, mm: %i, wt: %i",  
> tmp.tm_year, tmp.tm_mon, tmp.tm_mday, tmp.tm_hour, tmp.tm_min,  
> tmp.tm_wday);
>    QDateTime tdt (QDate (1900 + tmp.tm_year, 1 + tmp.tm_mon,  
> tmp.tm_mday), QTime (tmp.tm_hour, tmp.tm_min, tmp.tm_sec), Qt::UTC);
>    qDebug ("tdt: %s, local: %s", qPrintable (tdt.toString ()),  
> qPrintable (tdt.toLocalTime ().toString ()));
>
>    struct tm tmp2;
>    localtime_r (t_t, &tmp2);
>    qDebug ("y: %i, m: %i, d: %i, h: %i, mm: %i, wt: %i",  
> tmp2.tm_year, tmp2.tm_mon, tmp2.tm_mday, tmp2.tm_hour, tmp2.tm_min,  
> tmp2.tm_wday);
>    QDateTime tdt2 (QDate (1900 + tmp2.tm_year, 1 + tmp2.tm_mon,  
> tmp2.tm_mday), QTime (tmp2.tm_hour, tmp2.tm_min, tmp2.tm_sec),  
> Qt::UTC);
>    qDebug ("tdt2: %s", qPrintable (tdt2.toString ()));
>
> and this is the output:
>
> Res val: Sun Jun 22 00:00:00 1947
> y: 47, m: 5, d: 21, h: 21, mm: 0, wt: 6
> tdt: Sat Jun 21 21:00:00 1947, local: Sat Jun 21 22:00:00 1947
> y: 47, m: 5, d: 22, h: 0, mm: 0, wt: 0
> tdt2: Sun Jun 22 00:00:00 1947
>
> I would have expected QDateTime::toUTC and QDateTime::toLocalTime  
> to return the same time diff as gmtime / localtime
>
> Is this a bug - or where does this discrepancy come from?
>
> Frank
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx  
> with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>

--
 [ signature omitted ] 

Message 3 in thread

Dan White wrote:
> Silly Question One: What is the timezone setting on your machine ?
> Silly Question Two: Is there a reason you are messing about back in 
> 1947 ?

It's a simulation program meant to model economic recovery in Europe 
after World War II?  :)

--
 [ signature omitted ] 

Message 4 in thread

Frank Hemer wrote:
>y: 47, m: 5, d: 21, h: 21, mm: 0, wt: 6
>tdt: Sat Jun 21 21:00:00 1947, local: Sat Jun 21 22:00:00 1947
>y: 47, m: 5, d: 22, h: 0, mm: 0, wt: 0
>
>I would have expected QDateTime::toUTC and QDateTime::toLocalTime to
> return the same time diff as gmtime / localtime

It would have, if you did not have a negative date. QDateTime timezone 
rules depend on the Unix time_t, which starts in 1970.

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 5 in thread

On Saturday 05 April 2008 09:22:49 Thiago Macieira wrote:
> Frank Hemer wrote:
> >y: 47, m: 5, d: 21, h: 21, mm: 0, wt: 6
> >tdt: Sat Jun 21 21:00:00 1947, local: Sat Jun 21 22:00:00 1947
> >y: 47, m: 5, d: 22, h: 0, mm: 0, wt: 0
> >
> >I would have expected QDateTime::toUTC and QDateTime::toLocalTime to
> > return the same time diff as gmtime / localtime

I didn't mention before:
Timezone is Europe/Berlin

I'm developing a medical app, transmitting date of birth from a java server to a qt rich client.
Transmission format is a qint64 holding the milliseconds since Epoche (1970, 1, 1).

> It would have, if you did not have a negative date. QDateTime timezone 
> rules depend on the Unix time_t, which starts in 1970.

That would mean, QDateTime cannot be used for DateTimes before Epoche??
This is not mentioned in the docs.

Well, so what chance do I have to convert the msecs to a valid date?
time_t, as implemented in QDateTime doesn't help as it is only valid after the Epoche.
Setting the value manually (QDateTime (QDate (y, m, d), QTime (h, m, s)), xxx) doesn't
help either?

Frank

--
 [ signature omitted ] 

Message 6 in thread

Frank Hemer wrote:
>On Saturday 05 April 2008 09:22:49 Thiago Macieira wrote:
>> Frank Hemer wrote:
>> >y: 47, m: 5, d: 21, h: 21, mm: 0, wt: 6
>> >tdt: Sat Jun 21 21:00:00 1947, local: Sat Jun 21 22:00:00 1947
>> >y: 47, m: 5, d: 22, h: 0, mm: 0, wt: 0
>> >
>> >I would have expected QDateTime::toUTC and QDateTime::toLocalTime to
>> > return the same time diff as gmtime / localtime
>
>I didn't mention before:
>Timezone is Europe/Berlin
>
>I'm developing a medical app, transmitting date of birth from a java
> server to a qt rich client. Transmission format is a qint64 holding the
> milliseconds since Epoche (1970, 1, 1).
>
>> It would have, if you did not have a negative date. QDateTime timezone
>> rules depend on the Unix time_t, which starts in 1970.
>
>That would mean, QDateTime cannot be used for DateTimes before Epoche??

QDateTime can. The timezone database it uses can't.

>This is not mentioned in the docs.
>
>Well, so what chance do I have to convert the msecs to a valid date?
>time_t, as implemented in QDateTime doesn't help as it is only valid
> after the Epoche. Setting the value manually (QDateTime (QDate (y, m,
> d), QTime (h, m, s)), xxx) doesn't help either?

Use a full QDateTime (year, month, day, hour, minute and second) or 
whatever makes sense to you. Dates of birth and timezones don't make 
sense together.

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 7 in thread

On Saturday 05 April 2008 14:54:19 Thiago Macieira wrote:
> Frank Hemer wrote:
> >On Saturday 05 April 2008 09:22:49 Thiago Macieira wrote:
> >> Frank Hemer wrote:
> >> >y: 47, m: 5, d: 21, h: 21, mm: 0, wt: 6
> >> >tdt: Sat Jun 21 21:00:00 1947, local: Sat Jun 21 22:00:00 1947
> >> >y: 47, m: 5, d: 22, h: 0, mm: 0, wt: 0
> >> >
> >> >I would have expected QDateTime::toUTC and QDateTime::toLocalTime to
> >> > return the same time diff as gmtime / localtime
> >
> >I didn't mention before:
> >Timezone is Europe/Berlin
> >
> >I'm developing a medical app, transmitting date of birth from a java
> > server to a qt rich client. Transmission format is a qint64 holding the
> > milliseconds since Epoche (1970, 1, 1).
> >
> >> It would have, if you did not have a negative date. QDateTime timezone
> >> rules depend on the Unix time_t, which starts in 1970.
> >
> >That would mean, QDateTime cannot be used for DateTimes before Epoche??
> 
> QDateTime can. The timezone database it uses can't.

This would at least require a clear statement in the docs ...

> >Well, so what chance do I have to convert the msecs to a valid date?
> >time_t, as implemented in QDateTime doesn't help as it is only valid
> > after the Epoche. Setting the value manually (QDateTime (QDate (y, m,
> > d), QTime (h, m, s)), xxx) doesn't help either?
> 
> Use a full QDateTime (year, month, day, hour, minute and second) or 
> whatever makes sense to you. Dates of birth and timezones don't make 
> sense together.

First, date of birth was just an example, second, date of birth comes with full
 date _and_ time info from the database - timezone info included. Its a medical
database and the time of birth is a required info. So I have to
handle it properly.
Other timestamps _before_ 1970 also are stored in the same manner, so I have
to implement a clean solution.
Probably I have to implement timezone handling myself across platforms.

Still I think this should be handled by QDateTime ...

Frank

--
 [ signature omitted ] 

Message 8 in thread

Frank Hemer wrote:
>> >Well, so what chance do I have to convert the msecs to a valid date?
>> >time_t, as implemented in QDateTime doesn't help as it is only valid
>> > after the Epoche. Setting the value manually (QDateTime (QDate (y,
>> > m, d), QTime (h, m, s)), xxx) doesn't help either?
>>
>> Use a full QDateTime (year, month, day, hour, minute and second) or
>> whatever makes sense to you. Dates of birth and timezones don't make
>> sense together.
>
>First, date of birth was just an example, second, date of birth comes
> with full date _and_ time info from the database - timezone info
> included. Its a medical database and the time of birth is a required
> info. So I have to handle it properly.
>Other timestamps _before_ 1970 also are stored in the same manner, so I
> have to implement a clean solution.
>Probably I have to implement timezone handling myself across platforms.
>
>Still I think this should be handled by QDateTime ...

QDateTime handles only two timezones: Local and UTC. And it works fine 
under either.

The conversion between them requires information from the timezone 
database. On Unix systems, that database contains historical information, 
so all past dates should be correct. Unfortunately, that database uses 
time_t, so it has to be a positive value because some Unix systems have 
an unsigned time_t.

If a data falls outside the range of positive values in a 32-bit signed 
time_t, QDateTime will use the lowest or highest values (Jan 1st 1970 or 
Jan 19, 2038). The idea there is that we'll at least get the offset from 
GMT right, even if the DST information was lost.

But, come to think of it, we can do better: use the same day and month, 
but the lowest or highest year (1970 or 2037). At least there's a higher 
chance of getting DST right.

Anyways, that explains why you got different values:
1) QDateTime applied the rules for Jan 1st 1970 for your June 1947 date. 

2) In January 1970, Berlin was most likely in Central European Time 
(GMT+1)

3) In June 1947, Berlin was likely in Summer Time. But you're seeing 3 
hours ahead of GMT, which is either Double Summertime or Berlin was in a 
different timezone then.

4) you're assuming that the negative time_t worked with localtime().

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 9 in thread

On Saturday 05 April 2008 17:28, Thiago Macieira wrote:
> Frank Hemer wrote:
> >> >Well, so what chance do I have to convert the msecs to a valid date?
> >> >time_t, as implemented in QDateTime doesn't help as it is only valid
> >> > after the Epoche. Setting the value manually (QDateTime (QDate (y,
> >> > m, d), QTime (h, m, s)), xxx) doesn't help either?
> >>
> >> Use a full QDateTime (year, month, day, hour, minute and second) or
> >> whatever makes sense to you. Dates of birth and timezones don't make
> >> sense together.
> >
> >First, date of birth was just an example, second, date of birth comes
> > with full date _and_ time info from the database - timezone info
> > included. Its a medical database and the time of birth is a required
> > info. So I have to handle it properly.
> >Other timestamps _before_ 1970 also are stored in the same manner, so I
> > have to implement a clean solution.
> >Probably I have to implement timezone handling myself across platforms.
> >
> >Still I think this should be handled by QDateTime ...
>
> QDateTime handles only two timezones: Local and UTC. And it works fine
> under either.
>
> The conversion between them requires information from the timezone
> database. On Unix systems, that database contains historical information,
> so all past dates should be correct. Unfortunately, that database uses
> time_t, so it has to be a positive value because some Unix systems have
> an unsigned time_t.
>
> If a data falls outside the range of positive values in a 32-bit signed
> time_t, QDateTime will use the lowest or highest values (Jan 1st 1970 or
> Jan 19, 2038). The idea there is that we'll at least get the offset from
> GMT right, even if the DST information was lost.
>
> But, come to think of it, we can do better: use the same day and month,
> but the lowest or highest year (1970 or 2037). At least there's a higher
> chance of getting DST right.

That would definitely be better. Still this is not a solution for critical 
applications like mine.

> Anyways, that explains why you got different values:
> 1) QDateTime applied the rules for Jan 1st 1970 for your June 1947 date.
>
> 2) In January 1970, Berlin was most likely in Central European Time
> (GMT+1)
>
> 3) In June 1947, Berlin was likely in Summer Time. But you're seeing 3
> hours ahead of GMT, which is either Double Summertime or Berlin was in a
> different timezone then.
>
> 4) you're assuming that the negative time_t worked with localtime().

I wonder how this is handled in qt jambi?
You probably have to handle conversion between java.util.Date <-> QDateTime.
The java date is UTC - and for now (and me) it seems its calculations are 
correct even prior to the Epoche.

Frank

--
 [ signature omitted ] 

Message 10 in thread

On Sunday 06 April 2008 01:48:01 Frank Hemer wrote:
> > But, come to think of it, we can do better: use the same day and month,
> > but the lowest or highest year (1970 or 2037). At least there's a higher
> > chance of getting DST right.
>  [...]
> That would definitely be better. Still this is not a solution for critical 
> applications like mine.

Well, for critical applications I would not trust any kind of timezone database.
The only thing that sort-of-works is to fix a 0 and count "real" seconds from
there. Any "translation" into "human readable form" using month, days and
hours is bound to fail rather sooner then later - not to mention using such 
a format as "primary data".

Recently there was this discussion on the Gregorian changes, which took
300 years to spread across Europe alone. No way to handle that reliably...

> > Anyways, that explains why you got different values:
> > 1) QDateTime applied the rules for Jan 1st 1970 for your June 1947 date.

1947... well, there was a time when part of Germany had Moscow time.
Not sure this bites here, but it's not unlikely.

Incidentally, that boundary between Moscow and (something like) Central
European Time within Germany at that time did _not_ coincide with the
later border between East and West Germany.

So to get "proper" "time" you'd need not only need the GPS data of frontline
Russian and American tanks around May 9, 1945 (give or take a few days,
and kilometers, ...) but also take into account the speed and willingness
of local commanders setting up townhall clocks ;-)

Regards,
Andre'

--
 [ signature omitted ] 

Message 11 in thread

On Monday 07 April 2008 10:24:15 Andrà PÃnitz wrote:
> > > Anyways, that explains why you got different values:
> > > 1) QDateTime applied the rules for Jan 1st 1970 for your June 1947
> > > date.
>
> 1947... well, there was a time when part of Germany had Moscow time.
> Not sure this bites here, but it's not unlikely.

I have reviewed the timezone database and there are really, really weird rules 
there.

When they are able, the database keepers try to record historical information 
of the past, like double summer times observed in times of war. The database 
also contains the very useless local mean time of the city, as well as the 
leap second information. (December 31st, 23:59:60 and June 30th, 23:59:60, 
see wikipedia)

In any case, there's one interesting rule: dates before 1970 and after 2037 
are not keep strict. What matters is the 32-bit signed positive range of 
time_t.

I'll be making the following changes to fix this bug:
1) when the dates fall outside the range of 1970-01-01 and 2037-12-31, change 
only the year to match the upper or lower limit, but keep the day and month 
intact.

2) add some information to the documentation of QDateTime, specifically about 
the Julian/Gregorian switch in 1582 and the fact that the timezone database 
isn't precise for any date that isn't between 1970 and the present. And then 
for Unix only, since Windows has no concept of timezone database.

It's interesting to note that the choice of new year's day for calculating the 
GMT offset in QDateTime means there's a higher probability of being wrong 
than being right. The Northern Hemisphere spends more than half of the year 
in Summer Time and more than half of the world's population is in it. That 
means that, for a given date, there's a higher probability that DST rules 
should be applied instead of the official time.

For the Southern Hemisphere, it's the opposite: it spends less than half of 
the year in Summer Time. But, of course, since New Year's Day is in Summer, 
the probability that the offset wanted was the official time (instead of the 
DST one) is greater.

Timekeeping for past dates is very, very uncertain.

The concept of organised timezones as we know today didn't exist more than 50 
years ago. Many European countries before 1940 used local mean times: for 
example, the Netherlands' official time was 20 minutes ahead of GMT; in the 
UK, until 1900, the use of local mean time in each city was the rule.

Not only that, there's also the problem of the Gregorian/Julian switch, which 
happened in different countries at different times. And there's the problem 
of some countries tinkering with their calendars, like when Sweden decided to 
have a February 30th in 1712.

And you thought Y2K was complicated :-)

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 12 in thread

On Monday 07 April 2008 11:21, Thiago Macieira wrote:
> On Monday 07 April 2008 10:24:15 Andrà PÃnitz wrote:
> > > > Anyways, that explains why you got different values:
> > > > 1) QDateTime applied the rules for Jan 1st 1970 for your June 1947
> > > > date.
> >
> > 1947... well, there was a time when part of Germany had Moscow time.
> > Not sure this bites here, but it's not unlikely.
>
> I have reviewed the timezone database and there are really, really weird
> rules there.
> In any case, there's one interesting rule: dates before 1970 and after 2037
> are not keep strict. What matters is the 32-bit signed positive range of
> time_t.

Hmm - what about those systems that support the negative range, however 
precise or not that may be. Could qt support the negative range there too?
It seems that the system I'm working on supports that range - at least with 
its system calls. And because the data is entered in local time, it might 
internally be converted into a invalid utc time but will be accessed in local 
time again, so this deviation will never appear on  the users side.
Java seems to work that way (not really sure though) - very likely because of 
all the reasons you have mentioned before.

> I'll be making the following changes to fix this bug:
> 1) when the dates fall outside the range of 1970-01-01 and 2037-12-31,
> change only the year to match the upper or lower limit, but keep the day
> and month intact.
>
> 2) add some information to the documentation of QDateTime, specifically
> about the Julian/Gregorian switch in 1582 and the fact that the timezone
> database isn't precise for any date that isn't between 1970 and the
> present. And then for Unix only, since Windows has no concept of timezone
> database.

I see no clean way to transmit timestamps to a richclient other than in utc. 
Otherwise one could not support multiple clients in different timezones 
according to their individual setup.

I had the impression, conversion on windows and unix up to now are only based 
on qts internal calculation - did I overlook sth?

>
> Timekeeping for past dates is very, very uncertain.
>
> The concept of organised timezones as we know today didn't exist more than
> 50 years ago. Many European countries before 1940 used local mean times:
> for example, the Netherlands' official time was 20 minutes ahead of GMT; in
> the UK, until 1900, the use of local mean time in each city was the rule.
>
> Not only that, there's also the problem of the Gregorian/Julian switch,
> which happened in different countries at different times. And there's the
> problem of some countries tinkering with their calendars, like when Sweden
> decided to have a February 30th in 1712.
>
> And you thought Y2K was complicated :-)

Not really;-) Had some struggle with this timezone stuff before ... especially 
with the windows weird behavior.

I wonder how others handle this - any thoughts here?

Frank

--
 [ signature omitted ] 

Message 13 in thread

My first reaction would be that you might have to keep track of the  
time as a set of individual numbers (y, m, d/h, m, s) rather than a  
single number -- like ISO 8601 Date/Time notation
<http://en.wikipedia.org/wiki/ISO_8601>

The only other thing that comes to mind is the Julian Day system used  
by astronomers
<http://en.wikipedia.org/wiki/Julian_day>

I do not know if any of that will help, but they are possibilities.

Good luck.

On Apr 5, 2008, at 6:58 AM, Frank Hemer wrote:
> On Saturday 05 April 2008 09:22:49 Thiago Macieira wrote:
>> Frank Hemer wrote:
>>> y: 47, m: 5, d: 21, h: 21, mm: 0, wt: 6
>>> tdt: Sat Jun 21 21:00:00 1947, local: Sat Jun 21 22:00:00 1947
>>> y: 47, m: 5, d: 22, h: 0, mm: 0, wt: 0
>>>
>>> I would have expected QDateTime::toUTC and QDateTime::toLocalTime to
>>> return the same time diff as gmtime / localtime
>
> I didn't mention before:
> Timezone is Europe/Berlin
>
> I'm developing a medical app, transmitting date of birth from a  
> java server to a qt rich client.
> Transmission format is a qint64 holding the milliseconds since  
> Epoche (1970, 1, 1).
>
>> It would have, if you did not have a negative date. QDateTime  
>> timezone
>> rules depend on the Unix time_t, which starts in 1970.
>
> That would mean, QDateTime cannot be used for DateTimes before  
> Epoche??
> This is not mentioned in the docs.
>
> Well, so what chance do I have to convert the msecs to a valid date?
> time_t, as implemented in QDateTime doesn't help as it is only  
> valid after the Epoche.
> Setting the value manually (QDateTime (QDate (y, m, d), QTime (h,  
> m, s)), xxx) doesn't
> help either?
>
> Frank
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx  
> with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>

--
 [ signature omitted ]