Reputation: 12311
I have a table TAB with a timestamp (DT) and a value (VAL) per row.
DT NOT NULL TIMESTAMP(0) WITH LOCAL TIME ZONE
VAL NOT NULL NUMBER
I try to read and get the timestamps in UTC.
SELECT SYS_EXTRACT_UTC (dt) AS dtm, val FROM mytab;
Result in Sqlplus looks ok to me.
DTM VAL
---------------------------
30.03.19 23:00:00 124
31.03.19 00:00:00 125
31.03.19 01:00:00 126
31.03.19 02:00:00 127
31.03.19 03:00:00 128
31.03.19 04:00:00 129
31.03.19 05:00:00 130
Now I do the same in Java/JDBC.
java.sql.Timestamp ts = rs.getTimestamp ("dtm");
java.util.Date dt = rs.getDate ("dtm");
java.util.Date tm = rs.getTime ("dtm");
ZonedDateTime zdt = ts.toInstant ().atZone (ZoneOffset.UTC);
System.out.println("ts="+ts.toString() + " val="+rs.getDouble("wert") +
" dt=" + dt.toString() + " tm=" + tm.toString() +" zdt="+zdt);
And the result is not what I expected regarding timezones.
ts=2019-03-30 23:00:00.0 val=124.0 dt=2019-03-30 tm=23:00:00 zdt=2019-03-30T22:00Z
ts=2019-03-31 00:00:00.0 val=125.0 dt=2019-03-31 tm=00:00:00 zdt=2019-03-30T23:00Z
ts=2019-03-31 01:00:00.0 val=126.0 dt=2019-03-31 tm=01:00:00 zdt=2019-03-31T00:00Z
ts=2019-03-31 03:00:00.0 val=127.0 dt=2019-03-31 tm=02:00:00 zdt=2019-03-31T01:00Z
ts=2019-03-31 03:00:00.0 val=128.0 dt=2019-03-31 tm=03:00:00 zdt=2019-03-31T01:00Z
ts=2019-03-31 04:00:00.0 val=129.0 dt=2019-03-31 tm=04:00:00 zdt=2019-03-31T02:00Z
ts=2019-03-31 05:00:00.0 val=130.0 dt=2019-03-31 tm=05:00:00 zdt=2019-03-31T03:00Z
Why does ts have a double 3? I would expect it to be in UTC. The only correct time is in tm.
Why is that? Whats the problem here?
JRE 1.8 Oracle 12c Linux with local timezone CET/CEST
Upvotes: 0
Views: 1306
Reputation: 159086
Timezone CET/CEST switches to Daylight Savings Time on 2019-03-31 at 02:00:00, so it skips from 02:00:00 to 03:00:00.
getDate
returns a java.sql.Date
that is a java.util.Date
at 2019-03-31 at midnight, so no DST.
getTime
returns a java.sql.Time
that is a java.util.Date
at 1970-01-01 at given time, so no DST.
getTimestamp
returns a java.sql.Timestamp
that is a java.util.Date
at given date and time, so DST is applied, changing 02:00 to 03:00. However, the values from the database don't have time zone, so remaining values don't get shifted. This is a flaw in the handling of TIMESTAMP WITH LOCAL TIME ZONE
.
Converting java.sql.Timestamp
to java.time.Instant
will adjust for DST, so mangles the times.
Note that TIMESTAMP WITH LOCAL TIME ZONE
does not store a time zone, it just tell the client API to convert to session time zone on your behalf. The actual value in the database depends on the database time zone, not the client time zone or the session time zone.
Upvotes: 2
Reputation: 2115
From Java Doc: https://docs.oracle.com/javase/8/docs/api/java/sql/Timestamp.html Timestamp, A thin wrapper around java.util.Date that allows the JDBC API to identify this as an SQL TIMESTAMP value. It adds the ability to hold the SQL TIMESTAMP fractional seconds value, by allowing the specification of fractional seconds to a precision of nanoseconds. A Timestamp also provides formatting and parsing operations to support the JDBC escape syntax for timestamp values.
The precision of a Timestamp object is calculated to be either:
There are many ways to format the timestamp and one such example can be following:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Timestamp ts = Timestamp.valueOf("2019-03-30 23:00:00.0");
System.out.println(sdf.format(ts));
Upvotes: 1