JDBC SQL Time zone - java

I'm using Spring with apache commons BasicDataSource.
The time zone shows as GMT via:
SELECT ##global.time_zone, ##session.time_zone;
My input is in epoch time, 1386831420000 and 1386833220000, so the query should be like this:
SELECT * FROM table WHERE AND arrival_time BETWEEN '2013-12-12 06:57:00' AND '2013-12-12 07:27:00';
I enabled SQL profiing, and this is the query that actually gets executed, so I don't get the correct results:
SELECT * FROM table WHERE AND arrival_time BETWEEN '2013-12-12 01:57:00' AND '2013-12-12 02:27:00';
Notice that the times are off by 5 hours, since I am EST-5, and the time should be in GMT.
My question is: How can I tell MySQL or Spring JDBC not to use the client time zone, and simply to always use GMT?
Please comment if there is any detail I could add to solve the issue.

Try explicitly converting the date string into a date type using TO_DATE (or implementation specific date converter function)
SELECT *
FROM table
WHERE arrival_time BETWEEN
TO_DATE('2013-12-12 06:57:00', 'YYYY-MM-DD HH24:MI:SS')
AND
TO_DATE('2013-12-12 07:27:00', 'YYYY-MM-DD HH24:MI:SS')
The above example is in Oracle SQL but the principle of explicitly casting a date string to a date type is common throughout SQL implementations.

It sounds like the JDBC driver isn't properly detecting Mysql's time zone setting. You may need to specify the server's time zone in the connection string. Try adding
serverTimezone=UTC&useTimezone=true
to the connection string. For more information, refer to the JDBC doc at http://cs.wellesley.edu/~cs304/jdbc/connector-j.html#connector-j-reference

Related

Date is different that in database

In my Quarkus app I have object which is the same as a table in database that have a java.sql.Timestamp createDate field. In database example date is shown as a: 2022-02-17 18:16:00 in PST time but when I get the object through JPA from MySQL database as a Timestamp is: 2022-02-18 02:16:00.0 which looks like UTC time.
In application properties I have:
quarkus.hibernate-orm.jdbc.timezone = America/Los_Angeles
which means that database is configured in PST time.
Any ides why time zone is different in java object from database data?
I met the same issue.
In the datebase table time field, the time is different 8 oclock from the app server.

Map timezone in query from postgresql to jpql

I would like to map my postgresql query to jpql query in java. And I can't map "created AT time zone 'UTC' AT time zone 'Europe/Paris'" .
My postgresql query:
SELECT count(*), to_char(created AT time zone 'UTC' AT time zone 'Europe/Paris','DD-MM-YYYY')
from my_table GROUP BY to_char(created AT time zone 'UTC' AT time zone 'Europe/Paris','DD-MM-YYYY');
My jpql query:
Query query = em.createQuery("select count(z), to_char(z.created, 'DD-MM-YYYY'), z.formType from MyTableEntity z where z.created >= :startFrom and z.created <= :endTo GROUP BY to_char(z.created, 'DD-MM-YYYY'), z.formType ");
How can I group by my created field in timestamp 'Europe/Paris'? In database created field is saved in timestamp. AT time zone in jpql doesn't work.
You shouldn't use to_char to convert dates to a string at all. Let JPA handle the conversion. Also PostgreSQL can store a timestamp, but it does not store a time zone. It only stores the offset of the timezone at the given moment.
What you can do to get these results by date is casting to date, rather than using formatting. Here's how it would look as a native query:
SELECT count(*), cast(created AS date), form_type from my_table
GROUP BY cast(created AS date), form_type;
And in JPQL:
SELECT count(z), cast(z.created as date), z.formType from MyTableEntity z
where z.created between :startFrom and :endTo
GROUP BY cast(z.created as date), z.formType
The a between x and y statement is equivalent to a >= x and a <= y.
And if your database runs on a server who's default timezone is Europe/Paris, you don't need that timezone conversion. Alternatively you can run a native query to set the timezone for your current connection https://www.postgresql.org/docs/9.1/sql-set.html and then run your other queries.
SET SESSION TIME ZONE 'Europe/Paris'

How to disable conversion to UTC when storing OffsetDateTime in PostgreSQL

Given this table:
CREATE TABLE a(
t TIMESTAMP WITH TIME ZONE
);
And this simple JDBC code snippet:
DriverManager.getConnection(
"jdbc:postgresql://localhost:5432/dbname", "user", "password"
).use { connection ->
val nowSomeTimeZone = OffsetDateTime.now(ZoneOffset.of("+4"))
connection.prepareStatement("insert into a(t) values (?)").use { insertStmt ->
insertStmt.setObject(1, nowSomeTimeZone)
insertStmt.executeUpdate()
}
connection.createStatement().use { stmt ->
stmt.executeQuery("select * from a").use { resultSet ->
resultSet.next()
val t = resultSet.getObject(1, OffsetDateTime::class.java)
println("$nowSomeTimeZone -> $t")
}
}
}
Somewhere inside the JDBC stack an automatic conversion from +04:00 to UTC must be happening, because this is the println output:
2018-08-30T10:35:33.594+04:00 -> 2018-08-30T06:35:33.594Z
What's even more weird, when I look into the table using the psql console client, it shows me the timestamp in yet another time zone (which is my local time zone):
$ psql -h localhost -U username
dbname=> select * from a;
t
----------------------------
2018-08-30 08:35:33.594+02
Why does this conversion happen, and how can I disable it?
Disabling the conversion is not possible, because the PostgreSQL server strips the time zone information and stores timestamps always in UTC, even when you are explicitly using the type TIMESTAMP WITH TIME ZONE.
Quoting the PostgreSQL documentation:
For timestamp with time zone, the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone. If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system's TimeZone parameter, and is converted to UTC using the offset for the timezone zone.
Moreover, the documentation states:
We do not recommend using the type time with time zone (though it is supported by PostgreSQL for legacy applications and for compliance with the SQL standard). PostgreSQL assumes your local time zone for any type containing only date or time.
The weird behaviour described in the question is because
The JDBC driver always returns the timestamp in UTC
The psql console client converts the timestamp to the user's local time zone before displaying it, in this case German Time (+02:00)
Thanks to #RobbyCornelissen for the insights.

Oracle session timezone: Can Oracle DB session convert java.sql.Date to correct timezone?

We have an audit table( Columns/Types: ID/Number,.. Audited_Date/Date) which logs audit entries using prepared statements. Until now, for different contexts we set the database session timezone for the connection, after which we were using the CURRENT_DATE attribute for the audited_date column. THIS MEANT THAT THE DATE INSERTED INTO THE COLUMN IS IN THE TIMEZONE OF THE CONNECTION WHICH IS IMPORTANT.
Now, we have a new requirement to add different dates based on the supplied timestamps for the audit logs. Similar to the previous approach where the auditing engine didn't have to worry about the timezone, is there a way to set the date for the column, WITHOUT having to do something like this:
TimeZone timeZone = TimeZone.getTimeZone(timezone);
calendar.setTimeZone(timeZone);
preparedStatement.setDate(4, new java.sql.Date(userTimestampMillis), calendar);
I would really like NOT to do this because the timezone attribute is decided based on multiple attributes like system environments, and other parameters. The application uses ALTER SESSION SET TIME_ZONE="CONTEXT_TIMEZONE" in a global scope of the application where connections are fetched from.
Is there any way to let the DB session handle the timezone conversion?
These two approaches fail to convert the the timestamp to the DB session timezone. If i'm not wrong, they are using the JVM timezone.
FAIL1.
Timestamp timestamp = new Timestamp(userTimestampMillis);
preparedStatement.setTimestamp(4, timestamp);
FAIL2.
preparedStatement.setObject(4, new java.sql.Date(userTimestampMillis));
Any documentation is greatly appreciated.
DATEs are not time zone aware, so you probably want to work with something in the TIMESTAMP WITH TIME ZONE data type. You say you can correctly set the database session time zone, so you're mostly there. Say you're in Los Angeles and my database session is in Chicago:
alter session set time_zone = 'America/Chicago';
Session altered.
select current_timestamp from dual;
CURRENT_TIMESTAMP
---------------------------------------------
2018-07-27 20:30:28.672000000 AMERICA/CHICAGO
select cast( current_timestamp at time zone 'America/Los_Angeles' as date ) as d from dual;
D
-------------------
2018-07-27 18:30:28
So you basically need to use AT TIME ZONE to convert the TIMESTAMP WITH TIME ZONE into the correct time zone, then use CAST ( ... AS DATE ) to turn that into a DATE, which basically just trucates off the time zone information and doesn't do any conversion.

JDBC and oracle database timezone handling

I have created sample table in oracle DB as below
"CREATED_ON" TIMESTAMP (6),
"CREATED_ON_TIMEZONE" TIMESTAMP (6) WITH TIME ZONE,
"TIMEZONE_GMT" TIMESTAMP (6) WITH TIME ZONE
and inserted values from java as below
preparedStatement.setTimestamp(1, new Timestamp(new Date().getTime()));
preparedStatement.setTimestamp(2, new Timestamp(new Date().getTime()));
preparedStatement.setTimestamp(3, new Timestamp(new Date().getTime()) ,Calendar.getInstance(TimeZone.getTimeZone("UTC")));
JVM timezone in ASIA/CALCUTTA. I have used SQL developer to query data.
I just wanted to clear my understanding
The first column stored value as per local JVM without timezone since dataType is only timestamp i.e 29-NOV-17 07.04.28.014000000 PM. so for column with timstamp datatype DB stores value as of local JVM which is passed by JDBC driver and there is no conversion happening either JDBC side or DB side ?
Second column store value with TIMEZONE i.e 29-NOV-17 07.04.28.014000000 PM
ASIA/CALCUTTA. So does it mean DB stores value for column with timezone information provided by JDBC driver and there is no convrsion at DB side?
I want to store value in GMT so I set third parameter as GMT , it store value in GMT but timezone was still showing as of local JVM . i.e 29-NOV-17 01.34.28.014000000 PM ASIA/CALCUTTA
I was refering below article but my observations looks totally diffrent.
http://brian.pontarelli.com/2011/08/16/database-handling-for-timezones/
Problem is Java Timestamp does not contain any time zone information.
So you insert a TIMESTAMP value into a column of TIMESTAMP WITH TIME ZONE. In such case Oracle makes an implicit cast with FROM_TZ:
FROM_TZ(<your value>, SESSIONTIMEZONE)
Command preparedStatement.setTimestamp(3, new Timestamp(new Date().getTime()) ,Calendar.getInstance(TimeZone.getTimeZone("UTC"))); would be correct only after an ALTER SESSION SET TIME_ZONE = 'UTC';

Categories