Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Date Conversion in Spring is one day off

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

like image 631
Jerry Skidmore Avatar asked Jul 14 '15 05:07

Jerry Skidmore


2 Answers

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?

  • 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….

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.

like image 131
Basil Bourque Avatar answered Nov 10 '22 23:11

Basil Bourque


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();
}
like image 3
pavaniiitn Avatar answered Nov 10 '22 23:11

pavaniiitn