0

I am using JSON to get data from an HttpServlet for data object class definitions that are shared between the servlet and a java client. If I print out the response from the api call I can see that the instance variable is correct. Then when I map it using Jackson object mapper and look at the instance the value is wrong, always by one day lower then the date in the response and in the database.

The response looks like:

[{"coveragePK":3,"agentPK":2,"serviceCoveragePK":12,
  "coverageDate":"2018-02-27","duration":10,"remainder":1,
  "startTime":"07:30:00","query":""},
 {"coveragePK":4,"agentPK":2,"serviceCoveragePK":13,
  "coverageDate":"2018-02-27","duration":8,"remainder":2,
  "startTime":"10:00:00","query":""}]

and after I map it I get:

Date: 2018-02-26 which is printed with

java.sql.Date date = coverages[i].getCoverageDate();
System.out.println("Date: " + date.toString());

If I convert the sql.Date to a LocalDate the result is the same as one would expect.

I use the following to write the json where coverages is an ArrayList.

ObjectMapper mapper = new ObjectMapper();
String psWindows = mapper.writeValueAsString(coverages);
PrintWriter out = httpServletResponse.getWriter();
out.append(psWindows);

And I read the JSON with

ObjectMapper mapper = new ObjectMapper();
CoverageDO[] coverage = mapper.readValue(foo, CoverageDO[].class);
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Nefarious
  • 458
  • 6
  • 21

2 Answers2

0

I suspect the problem is in your timezone.

java.sql.Date stores the date like a timestamp (time since January 1, 1970, 00:00:00 GMT), but when it gets converted to java.util.Date. Try to use SimpleDateFormat to check the real date.

new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").parse(date);
Syl
  • 2,733
  • 2
  • 17
  • 20
0

tl;dr

LocalDate.parse( "2018-02-27" )

java.time

The java.sql.Date class is part of the troublesome old date-time classes that are now legacy, supplanted by the java.time classes.

LocalDate ld = LocalDate.parse( "2018-02-27" ) ;
LocalTime lt = LocalTime.parse( "10:00:00" ) ;

Generate a string representing that date’s value using standard ISO 8601 format by calling toString.

String output = ld.toString() ;

2018-02-27

Put those two together.

LocalDateTime ldt = LocalDateTime.of( ld , lt ) ;

ldt.toString(): 2018-02-27T10:00:00

A LocalDateTime lacks any concept of time zone or offset-from-UTC. As such, a LocalDateTime does not represent a moment, is not a point on the timeline. It represents a vague idea of potential moments along a range of about 26-27 hours.

To determine an actual moment, place it into the context of a time zone (or offset) if you are absolutely certain such a zone/offset was intended.

If I convert the sql.Date to a LocalDate

Don’t. No need to ever use java.sql.Date again. Just use LocalDate.

If you must inter-operate with old code not yet updated to java.time classes, then call new conversion methods added to the old classes.

LocalDate ld = myJavaSqlDate.toLocalDate() ;  // From legacy class to modern class.
java.sql.Date myJavaSqlDate = java.sql.Date.valueOf( ld ) ; // Vice-versa. From modern class to legacy 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.

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
  • Then I should store the date in the database as a long and you ld.toEpochDay() to store in database and just use this value everywhere. – Nefarious Feb 27 '18 at 21:07
  • @Nefarious Why not use date-time types in the database to store date-time values? For standard SQL type of `DATE`, exchange a `LocalDate` object: `myPreparedStatement.setObject( … , myLocalDate ) ;` and `LocalDate myLocalDate = myResultSet.getObject( … , LocalDate.class ) ;` – Basil Bourque Feb 27 '18 at 23:07
  • I haven't really tried it but my thought is general objects are not sql comparable. – Nefarious Feb 28 '18 at 00:14
  • @Nefarious The entire point of [JDBC](https://en.wikipedia.org/wiki/Java_Database_Connectivity) and [JDBC drivers](https://en.wikipedia.org/wiki/JDBC_driver) is to mediate between the Java types (classes/objects) and the database types. I suggest you study the [Oracle Tutorial on JDBC](https://docs.oracle.com/javase/tutorial/jdbc/TOC.html). – Basil Bourque Feb 28 '18 at 00:30
  • I wonder how JDBC makes any difference in a stored procedure? If I store an arbitrary object in the database then I can't compare against it in a stored procedure. – Nefarious Feb 28 '18 at 00:48
  • You never said anything about a stored procedure on your Question. We’re talking about Java here, in your Servlet. – Basil Bourque Feb 28 '18 at 02:45