10

I have a POST end-point that takes a couple of values, one being endDate and startDate. When the JSON posts in as:

{ "startDate" : "2015-01-30", "endDate" : "2015-12-30" }

Spring converts it to a java.util.Date Object that is always one day behind. In the logs I see:

Validating that startDate Thu Jan 29 16:00:00 PST 2015 < endDate Tue Dec 29 16:00:00 PST 2015

So it got the timezone correct. I had assumed it was related to UTC conversions, but I'm not sure how to configure this or modify it so that it converts it using the proper off-set. The timestamp portion of it isn't required - I only care that the year, day, and month match what is passed in.

if it matters, I'm using Spring (happened with 4.0.6 and 4.1.7) and a POST

Jerry Skidmore
  • 400
  • 2
  • 7
  • 20
  • please tell me what do you want – pavaniiitn Jul 14 '15 at 05:29
  • I want Spring to create a java.util.Date object that has "Thu Jan 30 XX:XX:XX PST 2015" for "2015-01-30" versus what it's doing now. I'm assuming there's a config setting that I'm missing. I don't understand why it's assuming 1/30/2015 UTC and then converting back to my time. – Jerry Skidmore Jul 14 '15 at 05:39
  • 1
    Check this link : http://stackoverflow.com/questions/2106525/java-incorrect-timezone Hope it helps. – Anand Jul 14 '15 at 06:39
  • FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Dec 26 '18 at 22:45
  • 1
    I am seeing the same issue. The date in PostMan shows as "2013-01-30" but Date variable is assigned Tue Jan 29 16:00:00 PST 2013 so it is one day off. The problem is I cannot switch to LocalDate due to legacy issues so I am forced to use java Date. The other reason is that JSF version we use does not support LocalDate – pixel Mar 12 '21 at 19:28

3 Answers3

6

tl;dr

LocalDate.parse( "2015-01-30" )

Use the right data type for the job

You are trying to fit a date-only value into a date-time type, java.util.Date. Square peg, round hole. While trying to come up with a time-of-day to associate with your date, a time zone is being injected, hence your problem.

LocalDate

Solution:

  • Never use the terrible old legacy date-time classes such as java.util.Date. Use only the modern java.time classes.

  • For a date-only value, use LocalDate.

Your input string happens to be in standard ISO 8601 format. The java.time classes use ISO 8601 formats by default when parsing/generating strings. So no need to specify a formatting pattern.

LocalDate ld = LocalDate.parse( "2015-01-30" ) ;

ZonedDateTime

If you want a moment, a date with a time-of-day, let java.time determine the first moment of the day. Never assume that moment is 00:00:00. In some zones on some dates it may be another time such as 01:00:00 because of anomalies such as Daylight Saving Time (DST).

ZonedId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;     // Let java.time determine the first moment of that date in that zone.

Instant

To adjust from to UTC (same moment, different wall-clock time), extract an Instant.

Instant instant = zdt.toInstant() ;  // Adjust to UTC. Same moment, same simultaneous point on the timeline, different wall-clock time.

Table of date-time types in Java (both legacy and modern) and in standard SQL


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?

Table of which java.time library to use with which version of Java or Android

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
    I'm having a similar issue with "@JsonFormat(pattern="yyyy-MM-dd") public Date birthdate;", in my Spring model, where Date is java.sql.Date, will I still be able to use @JsonFormat with LocalDate? – Devin Andres Salemi Oct 13 '19 at 04:54
  • @DevinAndresSalemi You should not be using `java.sql.Date` anymore, never again. For a date without time, use `LocalDate` class. I do not know where you got `@JsonFormat` but any decent framework should be updated for the *java.time* classes by now. See the table graphic I added. – Basil Bourque Oct 13 '19 at 04:57
  • I see, thanks, the motive was to use CallableStatement which requires Date, but basically I just need to use Spring Boot to persist a date to SQL Server, using a lot of stored procedures and raw JDBC – Devin Andres Salemi Oct 13 '19 at 05:36
  • Ended up using CallableStatement.SetObject and LocalDate, works perfect now! – Devin Andres Salemi Oct 13 '19 at 05:43
3
String str="2015-01-30";
try{
    SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd");
    isoFormat.setTimeZone(TimeZone.getTimeZone("PST"));
    Date date = isoFormat.parse(str);
    System.out.println(date);
}catch(ParseException e){
    e.printStackTrace();
}
pavaniiitn
  • 311
  • 1
  • 4
  • 18
  • If I pass it in as a string and convert to a date, there's no problem - it all works. It's when Spring does the conversion that there is a problem. So I start with java.util.Date and I need to convert it to one where the millis from epoch is centered around my timezone and not UTC – Jerry Skidmore Jul 14 '15 at 16:58
  • FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Dec 26 '18 at 22:45
0

Check here http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-webdatabinder how to customize automatic Spring conversion:

@Controller
public class MyFormController {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }
    // ...
}
michaldo
  • 4,195
  • 1
  • 39
  • 65