Query a mysql DATETIME with a given timezone in Java - java

I am trying to query a mysql DATETIME from Java. I know the the time zone of the server, but I cannot pull the datetime out with the time zone as I would expect.
ResultSet rs = st.executeQuery(...);
Date d1=rs.getTime(i, Calendar.getInstance(TimeZone.getTimeZone("UTC")));
Date d2=rs.getTime(i, Calendar.getInstance(TimeZone.getTimeZone("PST")));
System.out.println("d1: "+d1.getTime());
System.out.println("d2: "+d2.getTime());
This leaves me with:
d1: 40258000
d2: 40258000
Am I missing something basic here?
ResultSet.getDate() does take the Calendar into account. But I cant use it because it truncates the time info. It's still strange ResultSet.getTime() wouldn't handle any timezone conversions.

The documentation states:
This method uses the given calendar to construct an appropriate millisecond value for the time if the underlying database does not store timezone information.
So perhaps the database does store time zone information in this case?
What does your value in the database look like, and what is it supposed to represent?

An alternative approach would be letting the MySQL server convert the time zone:
SELECT CONVERT_TZ(timefield,'PST','UTC') AS tf
for example would convert the DATETIME value in the field timefield from PST to UTC time (and then returning it as tf).

getTime on the Date class returns the epoch time according to http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Date.html
so it would adjust out your timezone. I think that page implies you should use the timezone adjusted calendar to get your local time.

Related

Java, Oracle db - Timezone issues after trunc(nvl) strips timestamp from a datetime object

Trying to fix a bug in our reporting. Currently the issue is as stands:
At 9:45PM on 2/22 in PST someone submits a work order.
It hits our Oracle Database and normalizes to EST (our db is in EST, but we work with clients all over US).
In iReport, we are using the following:
trunc(nvl(ls.date_occurred,ls.date_created)) between TRUNC($P{DATE_FROM}) AND TRUNC($P{DATE_TO})
This STRIPS the timestamp off of the datetime object, so when the report is generated it does not save the hours, only the date which is now 2/23 (at 12:25 AM respectively).
This obviously throws off our reporting feature. All of the data seems to be correct except this date offset that is generated a day after because of the timezone difference, and the adjusted data not having a timestamp asociated with it.
Does anyone have another way to adjust for datetime without using a function that strips the timestamp off of the date?
As I understand your from/to dates are not in EST which makes the discrepancy between the dates you require in your report to the date in you Database. In order to get the correct records instead if truncating the dates you need to adjust the requested to/from dates according to the timezone of the request (If you request from PST timezone first convert the dates to EST then make the query)
also, you can look at : TIMESTAMP WITH TIME ZONE Datatype
https://docs.oracle.com/cd/B19306_01/server.102/b14225/ch4datetime.htm
Turns out that I need to adjust for the timezone of date_created inside the nvl, because date_occurred is trunced whereas date_created is not. This causes data loss.

MySQL DATETIME and TIMESTAMP to java.sql.Timestamp to ZonedDateTime

I am wondering how the conversion works in this. MySQL server (5.6) treats TIMESTAMP as zone-adjusted (and internally stored in/retrieved from UTC). It also treats DATETIME as having no zone.
On the Java side, I am recommended to read into java.sql.Timestamp in either case. Is there a zone-type conversion taking place (when going through MySQL-connector 5.1.37) from MySQL's DATETIME to java.sql.Timestamp (such as to apply the client system zone) ?
In the end, there is only one zone for my server and clients, and so I maintain a specific ZoneId (in app code) to get to ZonedDateTime. But I would like to work with ZonedDateTime, going back and forth to the database stored as DATETIME. A simple example of conversion will be appreciated!
Let's address each question you have. First: Is there a zone-type conversion taking place (when going through MySQL-connector 5.1.37) from MySQL's DATETIME to java.sql.Timestamp (such as to apply the client system zone)?
First off, I presume that you are using the getTimestamp(int) method from the connector. I could not find an official source that showed me an enlightening answer; however, there was this question in which the answer stated: When you call getTimestamp(), MySQL JDBC driver converts the time from GMT into default timezone if the type is timestamp. It performs no such conversion for other types.
However, in this version of the method, it uses an underlying Calendar to convert the Timestamp to the TimeZone specified, if the underlying database doesn't store time zone information. This may be the solution to your second question, as long as you knew the time zone at which the value was stored (which you do). But if it is not, it seems that with the first method there is no conversion taking place, at least when it retrieves the DATETIME. Speaking about your second question:But I would like to work with ZonedDateTime, going back and forth to the database stored as DATETIME.
It makes me think that there is a way to do this as long as you knew which time zone you are converting from. As we have previously stated, you and your clients are only working with one ZoneId, which is totally fine. However, this answer is provided to work with more time zones. Multiple ZoneId's can be achieved if you were to store the ZoneId of the connection in the database; retrieving it as well as the DATETIME and finally processing these values into a ZonedDateTime. You could store the ZoneIds into the database using the ID's of the ZoneId class (if you wanted to).
Timestamp t = resultSet.getTimestamp(timestampColumnId);
ZoneId zoneId = ZoneId.of(resultSet.getString(zoneColumnId), ZoneId.SHORT_IDS);
ZonedDateTime d = ZonedDateTime.ofInstant(t.toInstant(), zoneId);
Or, you could just store the DATETIME as a TIMESTAMP in the database as ZZ Coder suggests in his answer stated above. But, you could just use the ZoneId you have hard-coded as such:
Timestamp t = resultSet.getTimestamp(timestampColumnId);
ZonedDateTime d = ZonedDateTime.ofInstant(t.toInstant(), zoneId);
EDIT
Looking at the source code, on get or set calls using the getTimestamp(int, Calendar) or the setTimestamp(int, Timestamp, Calendar) function, the timezone of the Calendar is used. However, in some cases with TIMESTAMP, when a Calendar is not used, the JDBC then uses the time zone of the server. And according to the original poster, it worked (see comment below).

How to get time according to timezone

I am storing timezone value in database as +5:30 or +2:00 or -1:00
I am fetching data from database and changing time according to time zone in java.
Here I would like to know how can I get time according to saved timezone value.
Use Timezone and Calendar. And check SO before asking...
Examples here, or here
TimeZone tz = Calendar.getInstance().getTimeZone();
System.out.println(tz.getDisplayName());// (i.e. Moscow Standard Time)
System.out.println(tz.getID());
That should get the time zone that the computer the user is using has been set to.
Unless you want to use a complicated solution by pinging a server and making a server-side check to see where the IP came from, then that is the closest you're going to get.
Use SimpleDateFormat and setTimeZone
String timeZone = "GMT" + offset // offset is the value you store in the db( +5:30, -2:30)
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone(timeZone));
Date date = format.parse("2014-11-19T09:01:02");

How to refactor my date/time to allow for setting dates for my users based on their zone?

My code currently uses java dates.
Mysql has column datetime.
I want to allow users to set their timezones, and then in my application I will convert the dates to reflect their timezones.
I am using Spring mvc.
How can I do this?
The Datetime type in MySQL does not have timezone associated with it. Instead, by default Connector/J (the MySQL JDBC Driver) gets the date using the server timezone. There was a setting for changing that, but I don't know if it is documented, I had to look through the source to see how it works.
I could save the user's timezone it a different column as VARCHAR, and use that when creating the date objects. If you don't want to change all your data, you can populate the time_zone column with the server default timezone, and then gradually change the timezones for users. Using the following code you can get the UTC Timestamp. The Calendar/Date objects are quite a mess, an you would be better using Joda Time.
ResultSet rs = null;
Date date = rs.getDate("date");
TimeZone userTimeZone = TimeZone.getTimeZone(rs.getString("time_zone"));
Calendar c = Calendar.getInstance(userTimeZone);
c.set(1900 + date.getYear(), date.getMonth(),
date.getDate(), date.getHours(),
date.getMinutes(), date.getSeconds());
//what you are actually interested in
long utcTimestamp = c.getTimeInMillis();
The common strategy is to store date and time information in the database using UTC (+0) and then convert to/from the users time zone preference in the GUI layer.

Does Hibernate adjusting java.util.date (milliseconds) when I retrieve it from the db based on machine time?

So we use Hibernate for Object-relational mapping and we have a Student.java (POJO) and a registrationDate (java.util.date). We save the student object with this date '2012-01-05 10:00:00' and when we look at the db it looks right as we save it.
The issue is when we get it back from the db (student.getRegistrationDate) instead of returning us the right milliseconds in GMT it returns us a modified milliseconds based on our time zone (our time zone -3, the wrong date is '2012-01-05 13:00:00' ). Now this is not the the normal behavior of java.util.date because it doesn't hold time Zone information, so I'm worried if actually Hibernate is adjusting the milliseconds in the date object to match the server local time or it could be something else ?.
Note: I get the date by using date.getTime not with date.ToString.
Conversion happens to the timezone application is running into. As you already know the work-around. Check this - http://community.jboss.org/wiki/UserTypeForNon-defaultTimeZone.
If u want to use it as a Timestamp use java.sql.Timestamp instead of java.util.Date (which assumes Zulu time), which will properly take care of time zone.
Or you might try joda Time but with Hibernate and JodaTime, you might need a slight bit of work see this

Categories

Resources