0

Working against an Oracle Database. It has a DATE typed column and the select(simplified here for easy perusal) statement issued via JDBC PreparedStatement is as follows:

select  DATE1 from TYPE_TABLE  where TYPE_TABLE.DATE1 =  ?

The question mark parameter value at runtime is 2018-01-31 12:50:30.0 PST. We are setting the parameter via setTimeStamp API of the PreparedStatement class.The error that we are seeing on execution of the above select query is as follows:

java.sql.SQLDataException: ORA-01830: date format picture ends before 
converting entire input string 

I did search over SO and other sister sites of SE network and all the references I found are related to Inserting dates into the database without using proper format mask. But I didn't find anything related to select statements yet.

What could be the possible problem and the solution here?

P.S: The type of the DATE1 column is indeed of type DATE in the Oracle DB.

Edit: If the NLS_DATE_FORMAT parameter is the issue here, then what format should be used for the date value in question (i.e2018-01-31 12:50:30.0 PST) here?

Inquisitive
  • 7,476
  • 14
  • 50
  • 61

4 Answers4

2

tl;dr

You have not provided any code, so we cannot decipher the exact problem. But read on for some guidance.

Wrong data-type: Your problem may be due to passing a moment in UTC (java.sql.Timestamp) for comparison to a column of type DATE which lacks any zone/offset (not in UTC, not in any zone/offset).

Use JDBC 4.2 or later. Pass java.time objects rather than strings.

myPreparedStatement.setObject( 
    … , 
    LocalDateTime.of( 
        LocalDate.of( 2018 , Month.January , 23 ) , 
        LocalTime.of( 12 , 34 , 56 ) 
    ) 
)

Oracle DATE type

As others noted, the DATE type in Oracle 11g etc. is not a date-only value (it has a time-of-day), and is not defined as such in standard SQL. It is a date-time lacking zone/offset, perhaps analogous to SQL-standard TIMESTAMP WITHOUT TIME ZONE type. This means such a value is not a specific moment, only a rough idea about potential moments along a range of about 26-27 hours.

For a date-time value lacking any concept of time zone or offset-from-UTC, the class to use in Java is LocalDateTime.

LocalDate ld = LocalDate.of( 2018 , Month.January , 23 ) ;
LocalTime lt = LocalTime.of( 12 , 34 , 56 ) ;
LocalDateTime ldt = LocalDateTime.of( ld , lt ) ;

ldt.toString(): 2018-01-23T12:34:56

Tip: Keep in mind this is not a moment. If you want a moment, you’ll need to place this LocalDateTime in the context of a time zone (or offset-from-UTC). Do so by applying a ZoneId to get a ZonedDateTime object. Search Stack Overflow for more info and examples.

We are setting the parameter via setTimeStamp API of the PreparedStatement class.

A java.sql.Timestamp is for a moment, a specific point on the timeline, in UTC. The equivalent type in standard SQL is TIMESTAMP WITH TIME ZONE. This type is not appropriate for your Oracle DATE column – as discussed above, a Oracle DATE is not a moment.

Furthermore, you should no longer be using java.sql.Timestamp as it is now legacy, supplanted by the java.time.Instant class.

To retrieve a Oracle DATE value into Java:

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

Smart objects, not dumb strings

If the NLS_DATE_FORMAT parameter is the issue here, then what format should be used for the date value in question (i.e2018-01-31 12:50:30.0 PST) here?

Do not use strings at all. Exchange java.time objects with Oracle database using a JDBC driver compliant with JDBC 4.2 or later.

As of JDBC 4.2 and later, you can directly exchange java.time objects. No need for strings. No need for java.sql classes ever again when working with date-time values.

Avoid legacy date-time classes such as Date, Calendar, and Timestamp. These are terribly confusing, poorly designed, and all-around troublesome. Use only java.time classes.

For a SQL such as:

SELECT some_date FROM some_table  where some_date =  ? ;

…pass your LocalDateTime the placeholder to your PreparedStatement by calling setObject.

myPreparedStatement.setObject( … , ldt ) ;

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.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

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?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

Oracle stores date using 7 bytes. One byte each for Century, Year, Month, Day, Hours, Minutes and Seconds. So any string must be passed with a corresponding format string to specify how each component of that string will be parsed into the 7 byte date.

select DATE1 
  from TYPE_TABLE  
 where TYPE_TABLE.DATE1 = to_date('2018-01-31 12:50:30', 'yyyy-mm-dd hh24:mi:ss');

If no format is specified, Oracle uses the default format available in NLS_DATE_FORMAT parameter. If the default format does not match the string used, we get this error :

ORA-01830: date format picture ends before  converting entire input string
Barbaros Özhan
  • 59,113
  • 10
  • 31
  • 55
ArtBajji
  • 949
  • 6
  • 14
  • The JDBC should take care of the conversion. If you it manually you will risk a mismatch for different i18n environments. – fhossfel Mar 11 '18 at 16:58
  • @ArtBajji Do you think that the correct format was not specified while entering the dates into the DB? What should be the NLS_DATE_FORMAT for the date value given in the question? i.e `2018-01-31 12:50:30.0 PST` – Inquisitive Mar 11 '18 at 17:09
  • I am not a java pro. I am a database developer. From the database end, the format used by java and the date string are not matching to parse the seven pieces of data for date. NLS_DATE_FORMAT need not be changed. The correct format needs to be used by java. – ArtBajji Mar 11 '18 at 17:28
  • Also note that Timestamp and Date are two different datatypes in Oracle. Date holds data upto seconds. Timestamp holds data upto 9th decimal precision of a second, costing a maximum of 11 bytes. – ArtBajji Mar 11 '18 at 17:31
  • If the column in question is of DATE datatype, use a function that would convert your string into DATE and not TIMESTAMP. – ArtBajji Mar 11 '18 at 17:32
1

Oracle is not SQL compliant: The data type DATE contains hours, minutes and seconds.

Documentation says:

This datatype contains the datetime fields YEAR, MONTH, DAY, HOUR, MINUTE, and SECOND. It does not have fractional seconds or a time zone.

A timestamp should only be necessary if you go down to split seconds and/or you want to store timezone information.

Can you try with setDate()?

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
fhossfel
  • 2,041
  • 16
  • 24
0

A fair guess is that your JDBC driver will convert the Oracle Data type into a java.sql.TimeStamp or java.sql.Date type (and note that there are differences between java.util.Date and java.sql.Date, in terms of precision for example). In the case, for example, of a java.sql.Timestamp type, try specifying:

ret.value = java.sql.Timestamp(java.util.Date().getTime()); copy to clipboard
and see if this helps. Then you will be able to use:
ret.value = java.sql.Timestamp(system.parseDate(work.getString("yourDate"), 
    "yyyyMMddHHmmssz").getTime()); 
spandey
  • 1,034
  • 1
  • 15
  • 30
  • FYI… The `java.sql.Timestamp` & `java.sql.Date` classes are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/tutorial/datetime/TOC.html) classes as of [JDBC 4.2](https://jcp.org/aboutJava/communityprocess/mrel/jsr221/index2.html) and later. – Basil Bourque Mar 12 '18 at 00:16