Subject | AW: AW: [Firebird-Java] Timezones |
---|---|
Author | Steffen Heil |
Post date | 2009-11-04T20:54:46Z |
Hi again,
what I understood so far:
Firebird itself stores timestamps as kind of floating point value (more
exactly 8 bytes), where the integer part (or the first 4 bytes) describe the
day and the fraction part (or the last 4 bytes) describe the number of
1/10000 seconds into that day.
If this definition holds, then I suspect jaybirds interpretation is broken.
Example 1:
2009.10.25 02:59:59 MESZ = 2009.10.25 00:59:59 UTC
Java: 1256432399000 = Encoded: 55129,107990000
But one second LATER:
2009.10.25 02:00:00 MEZ = 2009.10.25 01:00:00 UTC
Java: 1256432400000 = Encoded: 55129,72000000
Example 2:
2009.03.29 01:59:59 MEZ = 2009.03.29 00:59:59 UTC
Java: 1238288399000 = Encoded to 54919,71990000
But one second LATER:
2009.03.29 03:00:00 MESZ = 2009.03.29 01:00:00 UTC
Java: 1238288400000 = Encoded: 54919,108000000
By definition I would expect the second fraction in increase by 10000 in
both examples.
This happens because jaybird ignores DTS in Germany. My local timezone is
CET = Europe/Berlin.
This means that jaybird can never encode certain values:
54919,72000000 to 54919,108000000
And there are multiple interpretations to other values:
55129,72000000 to 55129,107990000
ONE simple fix would be to encode the date using a calendar, then use
getTime(), add 1/10 of the time fraction and then use setTime().
This would fix the interpretation of the second part of timestamp byte array
pair.
(Note that then the range of valid values would depend on the date in
timezones with DTS. Most days would have 0-863.999.999, while one day would
be 0-827.999.999 and one day would be 0-899.999.999.)
The current implementation is really BROKEN because it doesn't even allow to
get the same values from the database that were stored earlier:
XSQLVAR v = new XSQLVAR();
Date original = parser.parse( "2009.10.25 02:30:00 MESZ" );
Date failure = v.decodeTimestamp( v.encodeTimestamp( new
java.sql.Timestamp( original.getTime() ) ) );
System.out.println( berlin.format( original ) + " -> " +
berlin.format( failure ) );
System.out.println( utc.format( original ) + " -> " + utc.format(
failure ) );
System.out.println( original.getTime() == failure.getTime() );
Prints:
2009.10.25 02:30:00 MESZ -> 2009.10.25 02:30:00 MEZ
2009.10.25 00:30:00 UTC -> 2009.10.25 01:30:00 UTC
false
From my POV this "false" is clearly a hard bug: The database driver discards
information.
Note that this bug exists involving A SINGLE TIMEZONE. The code above uses 3
distinct formatters just to show the problem more clearly. Just note that
you can leave out the first two println's.
Any comments?
Regards,
Steffen
[Non-text portions of this message have been removed]
what I understood so far:
Firebird itself stores timestamps as kind of floating point value (more
exactly 8 bytes), where the integer part (or the first 4 bytes) describe the
day and the fraction part (or the last 4 bytes) describe the number of
1/10000 seconds into that day.
If this definition holds, then I suspect jaybirds interpretation is broken.
Example 1:
2009.10.25 02:59:59 MESZ = 2009.10.25 00:59:59 UTC
Java: 1256432399000 = Encoded: 55129,107990000
But one second LATER:
2009.10.25 02:00:00 MEZ = 2009.10.25 01:00:00 UTC
Java: 1256432400000 = Encoded: 55129,72000000
Example 2:
2009.03.29 01:59:59 MEZ = 2009.03.29 00:59:59 UTC
Java: 1238288399000 = Encoded to 54919,71990000
But one second LATER:
2009.03.29 03:00:00 MESZ = 2009.03.29 01:00:00 UTC
Java: 1238288400000 = Encoded: 54919,108000000
By definition I would expect the second fraction in increase by 10000 in
both examples.
This happens because jaybird ignores DTS in Germany. My local timezone is
CET = Europe/Berlin.
This means that jaybird can never encode certain values:
54919,72000000 to 54919,108000000
And there are multiple interpretations to other values:
55129,72000000 to 55129,107990000
ONE simple fix would be to encode the date using a calendar, then use
getTime(), add 1/10 of the time fraction and then use setTime().
This would fix the interpretation of the second part of timestamp byte array
pair.
(Note that then the range of valid values would depend on the date in
timezones with DTS. Most days would have 0-863.999.999, while one day would
be 0-827.999.999 and one day would be 0-899.999.999.)
The current implementation is really BROKEN because it doesn't even allow to
get the same values from the database that were stored earlier:
XSQLVAR v = new XSQLVAR();
Date original = parser.parse( "2009.10.25 02:30:00 MESZ" );
Date failure = v.decodeTimestamp( v.encodeTimestamp( new
java.sql.Timestamp( original.getTime() ) ) );
System.out.println( berlin.format( original ) + " -> " +
berlin.format( failure ) );
System.out.println( utc.format( original ) + " -> " + utc.format(
failure ) );
System.out.println( original.getTime() == failure.getTime() );
Prints:
2009.10.25 02:30:00 MESZ -> 2009.10.25 02:30:00 MEZ
2009.10.25 00:30:00 UTC -> 2009.10.25 01:30:00 UTC
false
From my POV this "false" is clearly a hard bug: The database driver discards
information.
Note that this bug exists involving A SINGLE TIMEZONE. The code above uses 3
distinct formatters just to show the problem more clearly. Just note that
you can leave out the first two println's.
Any comments?
Regards,
Steffen
[Non-text portions of this message have been removed]