Hibernate stores Calendar as int when using SQLite - java

I am using Hibernate 4.3.8 along with a SQLite database (sqlite-jdbc-3.8.7.jar). Some of the mapped objects contain Calendar-attributes, e.g. startDate and endDate. After Hibernate got problems with reading dates in the format yyyy-MM-dd (e.g. 2015-01-01), I added the following line to hibernate.cfg.xml:
<property name="connection.date_string_format">yyyy-MM-dd</property>
Reading from the database works now, but when I save an object, Hibernate should save the date in the correct format but saves the time in milliseconds since 1970. After that, reading from the database again results in an error, since the columns now have values like 1427410800105, which are of course not the right format. Btw., I'm using the SQLiteDialect from here, there should be nothing wrong with that.
Are there maybe some annotations that can help me?
Personally, I only want to change some things in the configuration or in the dialect, I don't want to go through all my objects and do changes there. And of course I don't want to change the type Calendar to Date, because this would mean too much changes to the code.
UPDATE: Using #Temporal(value = TemporalType.DATE) does not work. The column entries stay the same.
UPDATE2: The same goes for #Column(columnDefinition = "calendar")

After some research I found the CalendarDateType. As I see it, Hibernate stores the Calendar attributes as timestamp by default. MySQL seems to convert this to a DATE or a DATETIME, but as SQLite has no such type, all date values are stored as TEXT. Saving a Calendar as timestamp results in these ugly numbers. To change the way Hibernate handles Calendar, just add the #Type-annotation:
#Type(type = "org.hibernate.type.CalendarDateType")
Calendar someAttribute;
If the Calendar should be saved in another format, you can define your own implementation of UserType like in this question: Hibernate - Mapping java.util.Calendar to MySQL BIGINT
UPDATE:
I tried to use the CalendarDateType from Hibernate, but for some reason, it didn't work. A quick look at the source code also shows that Hibernate uses another date format (dd MMMM yyyy), so it could make things problematic. To handle this I wrote my own implementation of UserType as described in the link above.

Related

Is Hibernate Using java.sql.Date Wrong?

I am reaching out to the community here because either I found an issue with Hibernate or I just don't understand how to use java.sql.Date and java.time.LocalDate.
I'm running into a problem where my DB is in UTC time zone while my client is in EST. I have a field in the DB called ETA of type DATE that for example is set to 2019-09-10 on a record. When I read the date in EST it becomes 2019-09-09. The DATE field according to documentation has no timezone information.
When Hibernate reads the value, it uses the DateTypeDescriptor.java class. However, the problem with that class is that it will first try to read the value as a java.sql.Date (in the rs.getDate( name ) part) and then call java.sql.Date.toLocalDate() in the javaTypeDescriptor.wrap() part, which is implemented poorly because what it does is it strips off the timezone offset information and just plainly returns a date. This makes 2019-09-09T20:00:00.000-0400 (which is 2019-09-10 in the database) to become 2019-09-09 without the timezone offset part.
What I consider the problem is the part where Hibernate calls rs.getDate() because that must return java.sql.Date. Now, the MySQL driver contains a method public LocalDate getLocalDate(int columnIndex) to obtain a LocalDate, so I don't understand why Hibernate isn't using that method.
I found that someone has already brought up this same problem with them but they don't seem to consider it an issue.
Therefore, I'm reaching out here to understand - is there a bug with Hibernate or am I just not understanding correctly how to convert between DATE (DB) and LocalDate (Java) types.
PS: I use latest Hibernate 5.4.5 and latest JPA 2.2.
Try Hibernate 5 and the configuration option hibernate.jdbc.time_zone. That's an official way to force it to use JDBC APIs which use an Calendar instance in the UTC timezone.
That said, I've found that there are a lot of problems in this area. JDBC drivers and people using databases often get this subtly wrong. That's why we eventually gave up and just put the milliseconds (in UTC) into the database. So the column type is always NUMBER(16) for all three temporal types.
That allows us to write special converters which return predictable results, independent of JDBC drivers, database/VM/OS time zones.
Programmers can then concentrate on trying to understand why timezones don't work they way they think they should :-)

DynamoDB table scan based on dates - Java

I've got a requirement, in my application, whereby I need to check a DynamoDB table for updates at regular intervals. Precisely, The field I need to check is not the hash key, and therefore I cannot query -- I need to scan.
The scan filter I am trying to build needs to check a field containing a date (coded as a String in the table), and the logic I am using is the one of asking all records created or updated in the last hour. The snippet I am using is below:
Condition scanFilterCondition = new Condition()
.withComparisonOperator(ComparisonOperator.BETWEEN.toString())
.withAttributeValueList(new AttributeValue().withS(new Date(currentTime-3600000).toString()),
new AttributeValue().withS(new Date(currentTime).toString()));
It seems to be correct, however it seems to always return an empty set so it is ovviously not correct.
I've been googling around to understand why this is not correct, however I haven't found anything around scanning/querying DyanmoDB on dates.
Any ideas on the fault?
Is the string written in the table as an EPOCH timestamp (e.g. 1382199953)? with or without milliseconds?
The default toString() returns a locale-based human-readable string (e.g. dow mon dd hh:mm:ss zzz yyyy).
If that's not the case, please comment with a sample data from the field in question.
Edit to support ISODateTime format using Joda:
DateTimeFormatter dateFormatter = ISODateTimeFormat.dateTime().withZoneUTC();
String isoDate = dateFormatter.print(currentTime);

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

How to specify Temporal type with JPA CriteriaBuilder?

I have a table that has a column with type of dateTime(I'm using SQL Server). I want to query the table by the dateTime column. I want rows that have the same date or later in the dateTime column, but I want to give the date as a parameter. In short, dateTime must be greater or equal than a specified date.
The problem I have is that when I try to query with Date object using criteria API, it only gives rows from the next day. I'm suspecting that it tries to find find rows with the same millisecond or later. In JPA query language I can specify the Temporal type of the parameter(setParameter("dateColumn",myDate,Temporal.DATE)) but I can't find anything similar in the CriteriaBuilder API. Any suggestions?
My code looks currently like this:
cb.greaterThanOrEqualTo(r.<Date>get(fieldName), beginDate));
Since I haven't gotten an answer I'm going to assume there is now way to this other than programmatically in your application.
If I want to do a query for entities that were created after this weeks monday I have to create a Date object, set the date to monday and clear the hours, minutes, seconds and milliseconds from the Date object. Apache Commons Lang library has a helper class for just this situation called DateUtils. It has method truncate which can be used to get the unnecessary accuracy out of the Date object so you can use greatedThanOrEqual in CriteriaBuilder.
You can use ParameterExpression :
ParameterExpression<Calendar> beginDateParameter = cb.parameter(Calendar.class);
...
...
criteriaQuery.select(...)
.where(criteriaBuilder.equal(r.get(fieldName), beginDateParameter));
entityManager.createQuery(criteriaQuery)
.setParameter(beginDateParameter, beginDate, TemporalType.DATE)
.getResultList();
Hibernate logs shows that date is passed as DateTime:
TRACE: org.hibernate.type.descriptor.sql.BasicBinder - binding parameter [0] as [DATE]
Well if I run the following class with DataNucleus JPA
#Entity
public class A
{
#Id
Long id;
#Temporal(TemporalType.DATE)
Date date;
}
this has the Date stored in a DATE column. And then run the following query
SELECT a FROM A a WHERE a.date >= :myDate"
passing in a java.util.Date as the parameter (including hour/min/second), it creates a query of
SELECT 'org.datanucleus.test.A' AS NUCLEUS_TYPE,A."DATE",A.ID,A."NAME" FROM A A WHERE A."DATE" >= <2009-06-15>
where the <2009-06-15> is a parameter to JDBC (the angle brackets are only shown to signify this), and I get no problems, i.e it correctly interprets the parameter as matching the type of what it compares against (which is what the JPA spec implies should happen)
Obviously if Hibernate has a problem with that you could pass in a java.sql.Date, and raise a bug on Hibernate

JDBC Bad format for DATE

I am trying to read several dates from my database but under certain circumstances I get a ' java.sql.SQLException Bad format for DATE'. Here is my code :
Date entryDateD = res.getDate("entryDate");
In debug mode I see that the content of entryDateD '1996-9-15' as is in my database..
Although I would have to mention that I read other dates too from my database which I notice are of the format 'xxxx-0y-zz'. What I want to say is that in case of a month being less than 10 there is a zero added in front of it which in this case is not added. I suspect that this might have something to do with it.
(this zero does not appear in the database itself though not only in this date but in any date)
thanx in advance :)
Just a guess, but what MySQL column type do you have for entryDate??
By default a date type in MySQL will generate an yyyy-mm--dd format; the missing zero leads me to believe that the column type may be varchar or other non-date type at DB level.
This could be the cause of your problems at Java level...
If you represent it as java.util.Date, you have the advantage of allowing the JDBC driver to worry about handling any format issues with the database.
As for how it's rendered in your display, that's up to you and your use of the java.text.DateFormat class.
You're doing the right thing by representing a date as java.util.Date in your app, but you need to understand that formatting is a separate issue from the type.
Java has a child class of java.util.Date, called java.sql.Date
The easiest way to create a Java SQL Date is by calling the constructor with a Utility Date.
java.util.Date uDate = res.getDate("entryDate");
java.sql.Date sDate = new java.sql.Date(uDate.getTime());
If you want to get res.getDate("entryDate") as YYYY-MM-DD then you need to cast as date in your query like this:
SELECT
...
CAST(entryDate as DATE)as entryDate,
...
FROM your_table;
If you feel this is helpful then do upVote to make it useful for others.

Categories

Resources