tags:

views:

3179

answers:

5

I get an exception (see below) if I try to do

resultset.getString("add_date");

for a JDBC connection to a MySQL database containing a DATETIME value of 0000-00-00 00:00:00 (the quasi-null value for DATETIME), even though I'm just trying to get the value as string, not as an object.

I got around this by doing

SELECT CAST(add_date AS CHAR) as add_date

which works, but seems silly... is there a better way to do this?

My point is that I just want the raw DATETIME string, so I can parse it myself as is.

note: here's where the 0000 comes in: (from http://dev.mysql.com/doc/refman/5.0/en/datetime.html)

Illegal DATETIME, DATE, or TIMESTAMP values are converted to the “zero” value of the appropriate type ('0000-00-00 00:00:00' or '0000-00-00').

The specific exception is this one:

SQLException: Cannot convert value '0000-00-00 00:00:00' from column 5 to TIMESTAMP.
SQLState: S1009
VendorError: 0
java.sql.SQLException: Cannot convert value '0000-00-00 00:00:00' from column 5 to TIMESTAMP.
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
    at com.mysql.jdbc.ResultSetImpl.getTimestampFromString(ResultSetImpl.java:6343)
    at com.mysql.jdbc.ResultSetImpl.getStringInternal(ResultSetImpl.java:5670)
    at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5491)
    at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5531)
+1  A: 

I suggest you use null to represent a null value.

What is the exception you get?

BTW:

There is no year called 0 or 0000. (Though some dates allow this year)

And there is no 0 month of the year or 0 day of the month. (Which may be the cause of your problem)

Peter Lawrey
ever heard of legacy systems
Schildmeijer
yes, but there is still no year called 0, even retrospectively. The year before 1 AD/CE was 1 BC/BCE
Peter Lawrey
That's the whole reason MySQL uses 0000 as an invalid date, because it doesn't conflict with existing dates. Also, dates like 1999-00-00 is sometimes used (not by me!) to represent the year 1999 rather than a specific day.
Jason S
+2  A: 

My point is that I just want the raw DATETIME string, so I can parse it myself as is.

That makes me think that your "workaround" is not a workaround, but in fact the only way to get the value from the database into your code:

SELECT CAST(add_date AS CHAR) as add_date

By the way, some more notes from the MySQL documentation:

MySQL Constraints on Invalid Data:

Before MySQL 5.0.2, MySQL is forgiving of illegal or improper data values and coerces them to legal values for data entry. In MySQL 5.0.2 and up, that remains the default behavior, but you can change the server SQL mode to select more traditional treatment of bad values such that the server rejects them and aborts the statement in which they occur.

[..]

If you try to store NULL into a column that doesn't take NULL values, an error occurs for single-row INSERT statements. For multiple-row INSERT statements or for INSERT INTO ... SELECT statements, MySQL Server stores the implicit default value for the column data type.

MySQL 5.x Date and Time Types:

MySQL also allows you to store '0000-00-00' as a “dummy date” (if you are not using the NO_ZERO_DATE SQL mode). This is in some cases more convenient (and uses less data and index space) than using NULL values.

[..]

By default, when MySQL encounters a value for a date or time type that is out of range or otherwise illegal for the type (as described at the beginning of this section), it converts the value to the “zero” value for that type.

Arjan
+8  A: 

I stumbled across this attempting to solve the same issue. The installation I am working with uses JBOSS and Hibernate, so I had to do this a different way. For the basic case, you should be able to add 'zeroDateTimeBehavior=convertToNull' to your connection URI as per:

http://dev.mysql.com/doc/refman/5.1/en/connector-j-reference-configuration-properties.html

I found other suggestions across the land referring to putting that parameter in your hibernate config:

In hibernate.cfg.xml:

<property name="hibernate.connection.zeroDateTimeBehavior">convertToNull</property>

In hibernate.properties:

hibernate.connection.zeroDateTimeBehavior=convertToNull

But I had to put it in my mysql-ds.xml file for JBOSS as:

<connection-property name="zeroDateTimeBehavior">convertToNull</connection-property>

Hope this helps someone. :)

sarumont
+1  A: 

DATE_FORMAT(column name, '%Y-%m-%d %T') as dtime

use this to avoid the error. It return the date in string format and then you can get it as a string.

resultset.getString("dtime");

Atul

That's kinda the same as my CAST(add_date AS CHAR) solution, but +1 since this lets you format it explicitly the way you want.
Jason S
+4  A: 

Alternative answer, you can use this JDBC URL directly in your datasource configuration:

jdbc:mysql://yourserver:3306/yourdatabase?zeroDateTimeBehavior=convertToNull

Edit:

Source: MySQL Manual

Datetimes with all-zero components (0000-00-00 ...) — These values can not be represented reliably in Java. Connector/J 3.0.x always converted them to NULL when being read from a ResultSet.

Connector/J 3.1 throws an exception by default when these values are encountered as this is the most correct behavior according to the JDBC and SQL standards. This behavior can be modified using the zeroDateTimeBehavior configuration property. The allowable values are:

  • exception (the default), which throws an SQLException with an SQLState of S1009.
  • convertToNull, which returns NULL instead of the date.
  • round, which rounds the date to the nearest closest value which is 0001-01-01.
Brian Clozel
interesting. where'd you find this info?
Jason S
just updated my answer! But @sarumont 's URL may fit better in this case (it lists all connector properties).
Brian Clozel