Does Oracle persist Java Calendar into TIMESTAMP with timezone? - java

We are persisting a Java Calendar object into an Oracle TIMESTAMP column using the getTimeInMillis() method. Does Oracle persist this data with a time zone?
I'm assuming not as we are not using the TIMESTAMP WITH TIMEZONE data type. If not, when you query SELECT MY_TIMESTAMP FROM MYTABLE what timezone will Oracle associate with this field?
And what is the correct way to 'cast' this to the timezone you are interested in (ie: UTC)?

getTimeInMillis()
is independent of the calendar system and the timezone. So in whichever timezone you specify the time in, the time is not gonna vary and getTimeInMillis() will get the accurate time.
And on the persistence -
yes the oracle persist the data with the timezone. But it will add the timezone offset to the value saved.
So that's brings us to the next question of choosing the right
timezone -
it is ideal to choose the native timezone. As this scenario is a combination of oracle and java its best to use UTC
Cheers!

Related

How to gather timezone of operating system from Oracle database in string format? (Migrate/convert date to ts with tz)

I want to update a database table which uses date type to timestamp with timezone type in such a way that the old dates get correct timezone information.
The plain cast is not good for me because if the time zone is for example UTC+2 hours (UTC+1 + 1 hour for daylightsaving) and I try to cast dates to timestamp with timezone, all the dates in the database table got the same +2 hour as timezone offset, regardless if it's a summer time or winter time date.
I already can write an SQL query which can determine about a date if it is in daylightsaving time or not, IF I know the current time zone in string format, e.g. 'Europe/Berlin'. The problem is that dbtimezone and sessiontimezone can be stored in other formats, too (+02:00, CET, etc). I cannot easily set the current sessiontimezone in a static way, because there are customers in several places on the globe with their own databases, but using a common update script.
Express method for timestamp can not help neither, because it cannot map the offset to named time zones.
I've seen a solution which uses java stored procedure to get the OS’s timezone instead of Oracles timezone. Unfortunately we use Oracle 12c, which contains an older JRE (I think it's 1.6 version). So, although Java 1.8 handles the timezones and daylight saving well (it uses updated tzmapping table), it does not work for me. I tryed it and if I run a test from Netbeans, then it gives me back the right time zone ID (in Europe/Berlin format), but even if it is accepted by Oracle SQL Developer, SQLPlus (which we use for running update scrips), it displays only +02:00.
I've tryied to use JodaTime (recompiled onto Java 1.6 in order to be accepted by SQL*Plus). The latest JodaTimes uses its own mapping table in theory. I read here on StackOverflow that if it cannot gather the time zone from user.timezone variable, then it turns to java.util, which is not good, as I mentioned. And if it does not succeed, then uses UTC. But it's not clear to me why it cannot get timezone from user.timezone systemm variable. Is it a permission problem maybe?
Or how could I possibly solve this issue? Thank you!
If the data is already in an Oracle SQL table, and you must convert to a timestamp with time zone (for example, in a new column you created in the same table), you do not need to go explicitly to the OS, or to use Java or any other thing, other than the Oracle database itself.
It is not clear from your question if you must assume the "date" was meant to be in the server time zone (you mention "the database" which normally means the server) or the client time zone (you mention "session" which means the client). Either way:
update <your_table>
set <timestamp_with_time_zone_col> =
from_tz(cast<date_col> as timestamp, dbtimezone)
;
or use sessiontimezone as the second argument, if that's what you need.
This assumes that the database (and/or the session) time zone is set up properly in the db, respectively in the client. If it isn't / they aren't, that needs to be fixed first. Oracle is perfectly capable of handling daytime savings time, if the parameters are set correctly in the first place. (And if they aren't, it's not clear why you would try to get your operation to be "more correct" than the database supports in the first place.)
Example: in the WITH clause below, I simulate a table with a column dt in data type date. Then I convert that to be a timestamp with time zone, in my session's (client) time zone.
with
my_table ( dt ) as (
select to_date('2018-06-20 14:30:00', 'yyyy-mm-dd hh24:mi:ss') from dual
)
select dt,
from_tz(cast(dt as timestamp), sessiontimezone) as ts_with_tz
from my_table
;
DT TS_WITH_TZ
------------------- -------------------------------------------------
2018-06-20 14:30:00 2018-06-20 14:30:00.000000000 AMERICA/LOS_ANGELES
The question in your title
How to gather timezone of operating system from Oracle database in string format?
is easy to answer. Run this statement:
SELECT TO_CHAR(SYSTIMESTAMP, 'tzr') FROM dual;
But I assume you have a different problem, however I don't fully understand it.
When you have a column of TIMESTAMP WITH TIME ZONE then the time zone information is available. Time zones like +02:00 do not have any daylight savings, it is always 2 hour ahead UTC, no matter if summer or winter. Timezones like Europe/Berlin or CET apply Daylight Saving Times.
If you have a time for example 2018-06-22 10:00:00+02:00 then you simply don't know whether this means Europe/Berlin with Daylight Saving Time on or Africa/Cairo which is always +02:00 hours ahead UTC - you have no possibility to retrieve such information!
If you have data in column of DATE (or TIMESTAMP) then you don't have any time zone information at all, thus you cannot convert such values to TIMESTAMP WITH TIME ZONE without further information.
Storing times in timezone of operating system is rather useless. Either store them in UTC or use data type TIMESTAMP WITH LOCAL TIME ZONE. Data in TIMESTAMP WITH LOCAL TIME ZONE are stored in DBTIMEZONE (which is recommended to be set as UTC but actually not relevant for you) and always and only shown in current user SESSIONTIMEZONE.

Hibernate Ignores DB Timezone Info when Binding to Java Timestamp Object

I have some Dates stored in Oracle with Oracle's TIMESTAMP(3) as its datatype. Now I'm writing a Spring boot app to read those values back. The code is like:
HibernateCallback callback = new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query query = session.createSQLQuery("SELECT date_field FROM some_table WHERE some_conditions");
return query.list();
}
};
So:
List results = (List)getHibernateTemplate().execute(callback);
// suppose there's only one row and one column returned
Timestamp ts = result.get(0)[0];
returns me the Java Timestamp object automatically created by Hibernate. The problem is that, when constructing the object, it ignores the timezone stored in Oracle, but instead uses JVM's default timezone. I tested is by setting different timezones for the JVM, and each time it generates a different timestamp.
It's obviously wrong. The Date should be unique on the time line. It shouldn't depend on JVM's timezone. I'm wondering what's the correct way to include the DB's timezone info when parsing the date. Right now it seems it's just using the String representation stored in Oracle and parse it with JMV's timezone. I'm using Hibernate 4.3.4.Final.
PS: The actual query is high customized so I have to write raw SQL.
Basically, that's not even an issue with Hibernate but with JDBC. By default, JDBC Driver will use system time zone on which JVM is running. If you are connecting to the DB server at a different time zone or even if you want to be independent of the current timezone of the system it is a good idea to set JDBC Time Zone explicitly.
You can use hibernate.jdbc.time_zone property to set the timezone or do it at runtime via.
session = sessionFactory.withOptions()
.jdbcTimeZone(TimeZone.getTimeZone("UTC"))
.openSession();
Also for Oracle, I would say you can use the TIMESTAMP WITH LOCAL TIME ZONE which will respect you JDBC client time zone.
The problem is with Oracle column data type you are using, If you go to official oracle docs, link, you will notice the TIMESTAMP doesn't respect timezone, so you should go with with either TIMESTAMP WITH TIME ZONE or TIMESTAMP WITH LOCAL TIME ZONE.
It seems the issue is with few concepts of date handling
Dates in DB should be in UTC, if they are to be used in multiple timezone.
Java program should convert the dates to required timezone.
If you take your date in database as based on UTC, and then check the output of your hibernate query, you should see that date is changed as per JVM's timezone.
If you want the same date back (as was in DB), maybe you should convert the date to UTC timezone.
Now, you can do either of following:
Set the JVM's timezone same as the database record timezone. Not recommended
Change your dates in database as per UTC, and let the dates be changed to JVM's timezone. Recommended

Copying TIMESTAMP to DATETIME on MySQL with Hibernate

I have these two classes
class Source {
// mapped to TIMESTAMP
#Version
#Column(columnDefinition="TIMESTAMP(3) DEFAULT '2016-01-01'")
Instant myInstant;
}
class Destination {
// mapped to DATETIME
#Basic(optional=true)
Instant myInstant;
}
When using Hibernate, I assign
destination.myInstant = source.myInstant;
and then the stored value is smaller by one hour than the original - both according to the command line MySQL client and in Java. My current timezone is UTC+1, so the reason is obviously a timezone conversion.
There are a few places where this can be fixed, but I'm looking for the best practice. The server should work world-wide, so it should continue to use UTC internally, right?
Should I just change the column type to TIMESTAMP? Then, why does Instant by default map to DATETIME?
According to this article, Instant does map to TIMESTAMP, but in my case it did not. Why?
If you want to work with timezones and Java 8 I would recommend using ZonedDateTime or OffsetTimeZone (the latter being prefered when working with Hibernate). For older versions use Calendar.
When you instance it should go by default with the timezone of your computer.
Check if the database is timestamp with or without timezone.
The default you set is also without timezone, and if it is "with timezone" it should automatically add the database's offset.
I hope some of this works. Here's how I did in one of my projects.
#Column(name = "registration_time")
private OffsetDateTime registrationTime;
[...]
subscriber.setRegistrationTime(OffsetDateTime.now());
In MySQL 5 & above, TIMESTAMP values are converted from the current time zone to UTC for storage, and converted back from UTC to the current time zone for retrieval. This occurs only for the TIMESTAMP data type but not for DATETIME. This is the reason you are seeing the difference while assigning a TIMESTAMP to DATETIME. So, having both the columns of same type should work. Hibernate by default maps InstantType to database TIMESTAMP type. Though you could use it for both TIMESTAMP and DATETIME in MYSQL, they are handled differently.

How to read timezone from 'timestamp with time zone' column?

I am unable to find a way to read timezone value in PostgreSQL column of type timestamp with time zone.
JDBC offers method java.sql.ResultSet#getTimestamp(int, java.util.Calendar)
but I must provide my own calendar. I have see no way to obtain that calendar from timestamp field I am reading.
I am working on system that stores time data of multiple timezones. I need to save data with timezone information, and be able to read that timezone back from database.
Is it possible without hacks like
storing timezone value in another field
storing date as string, like 'Wed 17 Dec 07:37:16 1997 PST'
I am using JDBC 41 (JDBC4 Postgresql Driver, Version 9.4-1201), java 8.
The PostgreSQL documentation here says that:
For timestamp with time zone, the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT).
So there is no need to "store the time zone [that corresponds to the timestamp value]" per se; the timestamp with time zone values are always stored as UTC.
Also, there is no need to "obtain the Calendar from the timestamp field". The purpose of the Calendar is for you to define the particular timezone that you want to work with in your Java application.
In other words, timestamp with timezone does not store values from various timezones (e.g., some in EST, others in PST, etc.), it converts everything to UTC when the timestamp values are inserted.
Accepted answer is true and accurate. timestamp with time type does not store timezone information in the field, and it is not possible to extract it.
If interested in timezone of the timestamp, it must be stored in separately (in other field, or in custom column type).
At first glance, it looks like that timezone may be extracted from timestamp with timezone using function extract(timezone from field), but it is not the case.
That function just gives 'time zone offset from UTC, measured in seconds'. Important (and not stated in documentation) part is that the offset is measured from current timezone (set by session SET SESSION TIME ZONE, or server timezone if not set). It is not offset that was used when saving field.

MongoDB, Java: Retrieve date property as UTC

I'm saving some entities to a Mongo database, these have Joda DateTime properties which have UTC set as a timezone. While saving works fine and I see the properties with correct values in the collection, once I retrieve the entities through Java the timezone gets set to UTC+2 again.
This is in the collection:
"created" : ISODate("2013-07-26T20:36:57.890Z")
I'm using Spring-Data-MongoDB to access the database.
Category category = mongoTemplate.findById(id, Category.class);
And I end up with this:
2013-07-26T23:05:56.439+02:00
Is there a way to tell Mongo do return the timezone stored in the date?
Hints appreciated, thank you!
The driver is returning what the database has as a java.util.Date object. It knows nothing of the timezone that time represents. It does not store the Timezone anywhere. Mongo Shell always presents a time value as UTC.
That being said, if you want to work with it in your application code as UTC always, I think there is a way to tell the JODA library to do this: Defaulting date time zone to UTC for Jodatime's DateTime

Categories