java.util.Date to java.sql.Date doesn't contain Time - java

I'm getting a SqlException on a PreparedStatement for violating a uniqueness constraint on a table (dupe key). Essentially my table looks like this:
mytable
=======
mytable_id PRIMARY KEY INT NOT NULL
fizz_id INT NOT NULL
buzz_timestamp DATETIME
The uniqueness constraint is on the buzz_timestamp; that is, no 2 records may have the same date/time "timestamp".
The PreparedStatement that inserts records into this table looks like this:
PreparedStatement ps = conn.prepareStatement(insertQuery);
ps.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
So you can see I'm taking java.util.Date() ("now") and converting it to a java.sql.Date instance.
The exact error I'm seeing (the dupe key) keeps complaining that I'm trying to insert 2015-05-27 00:00:00.0000000 into the table for buzz_timestamp, but that it already exists. So, obviously, I'm using the Date API wrong, and I'm inserting dates that have nulled-out time components, and thereby producing dupe key exceptions.
So I ask: How do I correct this so that I'm truly inserting the date and time for "now"?

Use
ps.setTimestamp(new java.sql.Timestamp(System.currentTimeMillis());
See this: Using setDate in PreparedStatement

The accepted answer is correct. I'll add an explanation.
Confusing Hack
In SQL, a DATE is a date-only value lacking a time-of-day or time zone.
The mess that is the old date-time classes bundled with Java lack any such class to represent date-only values.
Instead, the Java team created a hack. They created java.sql.Date by extending java.util.Date which, despite its confusing name, has a date portion and a time-of-day portion. For the SQL-oriented subclass, they set time-of-day portion to zero values. You might think of that as "midnight". So a java.sql.Date has a time-of-day but pretends not to.
To quote the java.SQL.Date doc:
To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.
For a date-and-time value in SQL use the java.sql.Timestamp class as shown in accepted answer.
java.time
These poorly designed date-time classes have been supplanted by the new java.time package built into Java 8 and later. This package was inspired by the Joda-Time library.
The Java.time package includes classes to represent date-only and time-only classes. Eventually the JDBC drivers will be upgraded to directly support the new data types. Until then, use the several conversion methods added to the old and new classes. Search StackOverflow.com for many examples and discussion, as this Question is largely a duplicate.

java.sql.Date extends java.util.Date but works differently: In SQL, DATE has no time. Therefore, the Java object also ignores hours, minutes, etc.
Try java.sql.Timestamp instead but you may need a cast (in SQL) to convert it to DATETIME.
Related:
mssql 2005 datetime and jdbc

Instead of setDate you need to try setTimestamp
java.sql.Date - A date only (no time part)
java.sql.Time - A time only (no date part)
java.sql.Timestamp - Both date and time

Related

Reliably retrieving dates and timestamps using JDBC [duplicate]

Is there anyway to get a java.time (new in Java 8) compatible time class out of a ResultSet?
I am aware you can use ResultSet's getDate or getTimestamp but these method return java.sql.Date / java.sql.Timestamp objects which are now deprecated so it seems like bad practice to use them in order to create a ZonedDateTime or similar.
Most database vendors don't support JDBC 4.2 yet. This specification says that the new java.time-types like LocalDate will/should be supported using the existing methods setObject(...) and getObject(). No explicit conversion is required and offered (no API-change).
A workaround for the missing support can be manual conversion as described on the Derby-mailing list.
Something like:
LocalDate birthDate = resultSet.getDate("birth_date").toLocalDate();
As you can see, these conversions use the non-deprecated types java.sql.Date etc., see also the javadoc.
New Methods On Timestamp
Java 8 includes new methods on the java.sql.Timestamp class to convert to and from java.time objects. These convenience methods are a stop-gap measure until JDBC drivers can be updated for the new data types.
toInstant
toLocalDateTime
valueOf
from
Ditto For Date & Time
The java.sql.Date and java.sql.Time classes have similar java.time conversion methods added in Java 8 as well.
Today most of us are using JDBC 4.2 compliant drivers, which improves the situation quite a bit compared to the answers from 2015.
To get a LocalDate from your result set:
LocalDate dateFromDatabase = yourResultSet.getObject(yourColumnIndex, LocalDate.class);
or
LocalDate dateFromDatabase = yourResultSet.getObject("yourColumnLabel", LocalDate.class);
No new method has been added to ResultSet for this to work. The getObject method was there all the time. The new thing is that since JDBC 4.2 it accepts LocalDate.class as the second argument and returns a LocalDate. The above works when the query returns a column with SQL datatype date (really the JDBC type counts, but they tend to agree).
You can pass classes of other java.time types too. And get the corresponding type back. For example:
OffsetDateTime dateTimeFromDatabase
= yourResultSet.getObject(yourTimestampWithTimeZoneColumnIndex, OffsetDateTime.class);
The java.time types to use are:
SQL datatype | java.time type
------------------------+-----------------------------------------------------------
date | LocalDate
time | LocalTime
timestamp | LocalDateTime
timestamp with timezone | Officially OffsetDateTime; many drivers accept Instant too
time with timezone | OffsetTime
For passing the other way, from Java to your database (for use as query parameters or for storing) PreparedStatement.setObject now accepts objects of the above java.time types too. Since you are passing an object of a type, there is no need for a separate type parameter when going this way.

Is it possible to choose which overridden method to use in Java?

I have a java.sql.Date instance and I want to use the java.util.Date.toInstant() method instead of java.sql.Date.toInstant(), for example, is it possible?
java.time and JDBC 4.2
I recommend that you stick to java.time, the modern Java date and time API to which Instant belongs and forget about the two Date classes mentioned in the question. They are both poorly designed and both long outdated. Since JDBC 4.2 we can retrieve java.time types from a ResultSet.
I am assuming that your SQL query is returning SQL datatype date.
PreparedStatement stmt = yourDatabaseConnection
.prepareStatement("select your_date_column from your_table;");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
LocalDate date = rs.getObject("your_date_column", LocalDate.class);
// do something with date
}
You want to convert the date to an Instant? That conversion doesn’t readily make sense. An SQL date usually is a calendar date defined by year, month and day of month, without time zone. An Instant is a point in time, a completely different beast. If you can decide on a time of day and a time zone to use, a conversion is possible. One option is:
Instant inst = date.atStartOfDay(ZoneId.systemDefault()).toInstant();
If you cannot avoid getting a java.sql.Date
Having a java.sql.Date, again we need a time of day and a time zone if we want to convert to Instant. There is a reason why java.sql.Date.toInstant() unconditionally throws UnsupportedOperationException (which I guess caused you to ask the question). I would convert the Date to a LocalDate and then proceed as before:
java.sql.Date oldfashionedSqlDate = getFromSomewhere();
Instant inst = oldfashionedSqlDate.toLocalDate()
.atStartOfDay(ZoneId.systemDefault())
.toInstant();
A shorter but more low-level and cryptic alternative is:
Instant inst = Instant.ofEpochMilli(oldfashionedSqlDate.getTime());
The two ways may not always give the same result, which should be your first guidance for choosing. In case the Date contrary to the specification holds a time of day other than the start of day, the latter method will give you that time, whereas the former will give you the start of the day as the code says. BTW the latter is what java.util.Date.toInstant() does.
In general is it possible to circumvent the method implementation in the subclass and call the superclass method directly?
Is it possible to choose which overridden method to use in Java?
No, that is not possible in the language. Java doesn’t offer any syntax for such a trick. Holger’s comment under this answer seems to suggest that it is possible through reflection under some circumstances such as you being able to open the java.base module. See the last link at the bottom for more details.
Links
Related question: Insert & fetch java.time.LocalDate objects to/from an SQL database such as H2
Oracle tutorial: Date Time explaining how to use java.time.
Related question: I want to print hi GrandFather;but it seems to print hi father
To answer your question as asked:
It is not possible for your code that uses a java.sql.Date to call an method in java.util.Date which java.sql.Date overrides.
That would break data abstraction, and the Java language doesn't allow it. You can't even do it reflectively.
(As other answers and comments indicate, there are alternative approaches that avoid this problem. Some more practical than others1.)
1 - The idea of creating a custom subtype of java.sql.Date is not practical. You don't want to be modifying JDBC drivers to try to solve this.

What is difference between java.utill.Time and java.sql.time [duplicate]

java.util.Date vs java.sql.Date: when to use which and why?
Congratulations, you've hit my favorite pet peeve with JDBC: Date class handling.
Basically databases usually support at least three forms of datetime fields which are date, time and timestamp. Each of these have a corresponding class in JDBC and each of them extend java.util.Date. Quick semantics of each of these three are the following:
java.sql.Date corresponds to SQL DATE which means it stores years, months and days while hour, minute, second and millisecond are ignored. Additionally sql.Date isn't tied to timezones.
java.sql.Time corresponds to SQL TIME and as should be obvious, only contains information about hour, minutes, seconds and milliseconds.
java.sql.Timestamp corresponds to SQL TIMESTAMP which is exact date to the nanosecond (note that util.Date only supports milliseconds!) with customizable precision.
One of the most common bugs when using JDBC drivers in relation to these three types is that the types are handled incorrectly. This means that sql.Date is timezone specific, sql.Time contains current year, month and day et cetera et cetera.
Finally: Which one to use?
Depends on the SQL type of the field, really. PreparedStatement has setters for all three values, #setDate() being the one for sql.Date, #setTime() for sql.Time and #setTimestamp() for sql.Timestamp.
Do note that if you use ps.setObject(fieldIndex, utilDateObject); you can actually give a normal util.Date to most JDBC drivers which will happily devour it as if it was of the correct type but when you request the data afterwards, you may notice that you're actually missing stuff.
I'm really saying that none of the Dates should be used at all.
What I am saying that save the milliseconds/nanoseconds as plain longs and convert them to whatever objects you are using (obligatory joda-time plug). One hacky way which can be done is to store the date component as one long and time component as another, for example right now would be 20100221 and 154536123. These magic numbers can be used in SQL queries and will be portable from database to another and will let you avoid this part of JDBC/Java Date API:s entirely.
LATE EDIT: Starting with Java 8 you should use neither java.util.Date nor java.sql.Date if you can at all avoid it, and instead prefer using the java.time package (based on Joda) rather than anything else. If you're not on Java 8, here's the original response:
java.sql.Date - when you call methods/constructors of libraries that use it (like JDBC). Not otherwise. You don't want to introduce dependencies to the database libraries for applications/modules that don't explicitly deal with JDBC.
java.util.Date - when using libraries that use it. Otherwise, as little as possible, for several reasons:
It's mutable, which means you have to make a defensive copy of it every time you pass it to or return it from a method.
It doesn't handle dates very well, which backwards people like yours truly, think date handling classes should.
Now, because j.u.D doesn't do it's job very well, the ghastly Calendar classes were introduced. They are also mutable, and awful to work with, and should be avoided if you don't have any choice.
There are better alternatives, like the Joda Time API (which might even make it into Java 7 and become the new official date handling API - a quick search says it won't).
If you feel it's overkill to introduce a new dependency like Joda, longs aren't all that bad to use for timestamp fields in objects, although I myself usually wrap them in j.u.D when passing them around, for type safety and as documentation.
tl;dr
Use neither.
java.time.Instant replaces java.util.Date
java.time.LocalDate replaces java.sql.Date
Neither
java.util.Date vs java.sql.Date: when to use which and why?
Both of these classes are terrible, flawed in design and in implementation. Avoid like the Plague Coronavirus.
Instead use java.time classes, defined in in JSR 310. These classes are an industry-leading framework for working with date-time handling. These supplant entirely the bloody awful legacy classes such as Date, Calendar, SimpleDateFormat, and such.
java.util.Date
The first, java.util.Date is meant to represent a moment in UTC, meaning an offset from UTC of zero hours-minutes-seconds.
java.time.Instant
Now replaced by java.time.Instant.
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC.
java.time.OffsetDateTime
Instant is the basic building-block class of java.time. For more flexibility, use OffsetDateTime set to ZoneOffset.UTC for the same purpose: representing a moment in UTC.
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
You can send this object to a database by using PreparedStatement::setObject with JDBC 4.2 or later.
myPreparedStatement.setObject( … , odt ) ;
Retrieve.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
java.sql.Date
The java.sql.Date class is also terrible and obsolete.
This class is meant to represent a date only, without a time-of-day and without a time zone. Unfortunately, in a terrible hack of a design, this class inherits from java.util.Date which represents a moment (a date with time-of-day in UTC). So this class is merely pretending to be date-only, while actually carrying a time-of-day and implicit offset of UTC. This causes so much confusion. Never use this class.
java.time.LocalDate
Instead, use java.time.LocalDate to track just a date (year, month, day-of-month) without any time-of-day nor any time zone or offset.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate ld = LocalDate.now( z ) ; // Capture the current date as seen in the wall-clock time used by the people of a particular region (a time zone).
Send to the database.
myPreparedStatement.setObject( … , ld ) ;
Retrieve.
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The only time to use java.sql.Date is in a PreparedStatement.setDate. Otherwise, use java.util.Date. It's telling that ResultSet.getDate returns a java.sql.Date but it can be assigned directly to a java.util.Date.
I had the same issue, the easiest way i found to insert the current date into a prepared statement is this one:
preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
The java.util.Date class in Java represents a particular moment in time (e,.g., 2013 Nov 25 16:30:45 down to milliseconds), but the DATE data type in the DB represents a date only (e.g., 2013 Nov 25). To prevent you from providing a java.util.Date object to the DB by mistake, Java doesn’t allow you to set a SQL parameter to java.util.Date directly:
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, d); //will not work
But it still allows you to do that by force/intention (then hours and minutes will be ignored by the DB driver). This is done with the java.sql.Date class:
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, new java.sql.Date(d.getTime())); //will work
A java.sql.Date object can store a moment in time (so that it’s easy to construct from a java.util.Date) but will throw an exception if you try to ask it for the hours (to enforce its concept of being a date only). The DB driver is expected to recognize this class and just use 0 for the hours. Try this:
public static void main(String[] args) {
java.util.Date d1 = new java.util.Date(12345);//ms since 1970 Jan 1 midnight
java.sql.Date d2 = new java.sql.Date(12345);
System.out.println(d1.getHours());
System.out.println(d2.getHours());
}
java.util.Date represents a specific instant in time with millisecond precision. It represents both date and time information without timezone. The java.util.Date class implements Serializable, Cloneable and Comparable interface. It is inherited by java.sql.Date, java.sql.Time and java.sql.Timestamp interfaces.
java.sql.Date extends java.util.Date class which represents date without time information and it should be used only when dealing with databases. To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.
It inherits all public methods of java.util.Date such as getHours(), getMinutes(), getSeconds(), setHours(), setMinutes(), setSeconds(). As java.sql.Date does not store the time information, it override all the time operations from java.util.Dateand all of these methods throw java.lang.IllegalArgumentException if invoked as evident from their implementation details.

Drop Time stamp while pulling data from oracle table to java

Currently I am getting date from oracle table as string which is giving me date as well as timesstamp. Is there a way I can drop timestamp and just get the date from table. Currently in my java code Date is declare as string which pulls date and timestamp.Thank you
setDate(rset.getString(1));
Using ResultSet#getDate() will return just the date component, as a java.sql.Date (which has hours, minutes, seconds, and milliseconds set to zero). You can turn that Date object into a string afterwards.
I would, however, recommend storing date information as a Date, not as a String.
Be careful of using the term "timestamp". Timestamp is a datatype in Oracle.
If you're asking how do you eliminate the 'time' portion of the date. You can use the TRUNC() function in Oracle. Or you could NOT use a string on the Java side, use a date instead and set the format to not show the time portion.
java.time
If your JDBC driver supports JDBC 4.2 or later, it may be able to handle the java.time types which supplant the old java.util.Date/.Calendar and java.sql types. Call the setObject method on a PreparedStatement and getObject on the ResultSet.
Date-only types will appear in Java as java.time.LocalDate. Time-of-day-only types will appear in Java as java.time.LocalTime. A timestamp (a date-time) will appear as an java.time.Instant.
If your driver does not yet offer this support, fall back to using the java.sql types as shown in the correct Answer by Matt Ball. Then immediately convert to java.time types. Perform your business logic in java.time types; use java.sql types only for data-exchange with database. Look to new methods added on the old classes for convenient conversions.
LocalDate ld = myJavaSqlDate.toLocalDate() ;
LocalTime lt = myJavaSqlTime.toLocalTime() ;
Instant instant = myJavaSqlTimestamp.toInstant() ;
Going the other direction, look at the valueOf or from methods.

A datetime equivalent in java.sql ? (is there a java.sql.datetime ?)

So far, I have not found a clear answer to this.
I'd like to know what the equivalent is for a SQL type DATETIME and the java type, using a PreparedStatement.
I have found: http://www.java2s.com/Code/Java/Database-SQL-JDBC/StandardSQLDataTypeswithTheirJavaEquivalents.htm
But it states that SQL type "DATETIME" is the same as sql.date, but when looking at the SQL date docs (http://download.oracle.com/javase/7/docs/api/java/sql/Date.html), it says the time is truncated (all zeros).
What I want is to be able to specify a preparedStatement.setDateTime() or some sort.
The only other way I see is using a timestamp, but that would require me to change the column type, while I cannot imagine someone else never had this problem before?
Any hints?
Edit: I am using MYSQL.
The java.sql package has three date/time types:
java.sql.Date - A date only (no time part)
java.sql.Time - A time only (no date part)
java.sql.Timestamp - Both date and time
You want the last one: java.sql.Timestamp.
If you are using these types, you don't need to call a specific setter; just use:
java.util.Date date = new Date();
Object param = new java.sql.Timestamp(date.getTime());
// The JDBC driver knows what to do with a java.sql type:
preparedStatement.setObject(param);
The equivalent of MS SQL Server or MySQL DATETIME data type or Oracle DATE data type is java.sql.Timestamp.
In Java we have java.util.Date to handle both Date and Time values.
In SQL, you have commonly Dates (only dates), Time (only time) and DateTime/Timestamp (date and time).
In your Java program, usually you'll always have java.util.Date, so each time you're setting Dates/Times/DateTimes in PreparedStatements, always choose exactly which one you need, according to the database.
I had a similar problem with my Mysql having SQL date and locally in my app i only had Date
I solved like this
java.sql.Date dataStartSql = new java.sql.Date(start.getTime());
After that used the setDate normally, and I used a getTimestamp to retrive the first value.
where start is a Date object.

Categories

Resources