0

I have a json formatted response Date to the controller that is like this:

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "America/Chicago")
private Date date;

So when I make a post call, it would look like:

"date": "2021-08-20 14:17:43"

So the response string would look something like this {"date":"2021-05-21 14:23:44"}. In JUnit, I am manually creating a response object and setting the Date object so I can then use Gson to turn it into a string and then assert that the two are equal. I am trying to match this in my SpringMVC JUnit test case by trying to do:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
        
String formattedDate = sdf.format(new Date());
LocalDate localDate = LocalDate.parse(formattedDate);
        
Date date = Date.from(localDate.atStartOfDay(ZoneId.of("America/Chicago")).toInstant());

But it is having an error parsing it because of the space between yyyy-MM-dd and HH:mm:ss:

java.time.format.DateTimeParseException: Text '2021-08-20 14:23:44' could not be parsed, unparsed text found at index 10

I think I may be doing this inefficiently, so I was wondering if there was a more simple way to make a Date object that would match the format of @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "America/Chicago")

I'm trying to match the response body so it passes via mockito.

8
  • Instead of SimpleDateFormat, You can instead use java.time.format.DateTimeFormatter like so: String formattedDate = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.of("America/Chicago")).format(LocalDateTime.now()); Commented Aug 20, 2021 at 20:14
  • Is there a way to get this to be a Date object? Because I need to do use the setter to set the date object. Commented Aug 20, 2021 at 20:18
  • I recommend you don’t use Date. That class is poorly designed and long outdated. Instead use only LocalDateTime and/or Instant from java.time, the modern Java date and time API. Commented Aug 21, 2021 at 2:53
  • Does this answer your question? want current date and time in “dd/MM/yyyy HH:mm:ss.SS” format? And/or this? Commented Aug 21, 2021 at 16:13
  • Which scenario exactly do you want your unit test to test? Creation of a response object in Java? Converting a response object to JSON? Converitng JSON to a Java object? Sorry, it’s unclear. Commented Aug 23, 2021 at 5:08

4 Answers 4

1

Do not mix the modern and the legacy Date-Time API

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String strDate = "2021-08-20 14:17:43";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s", Locale.ENGLISH);
        LocalDateTime ldt = LocalDateTime.parse(strDate, dtf);
        System.out.println(ldt);

        // Get the required Instant
        ZonedDateTime zdtUtc = ldt.atZone(ZoneOffset.UTC);
        ZonedDateTime zdtChicago = zdtUtc.withZoneSameInstant(ZoneId.of("America/Chicago"));
        Instant instant = zdtChicago.toInstant();
        System.out.println(instant);
    }
}

Output:

2021-08-20T14:17:43
2021-08-20T14:17:43Z

ONLINE DEMO

java.time

The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*. However, for any reason, if you need to convert this object of Instant to an object of java.util.Date, you can do so as follows:

Date date = Date.from(instant);

Learn more about the modern Date-Time API from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Sign up to request clarification or add additional context in comments.

9 Comments

The problem with this, is that the Date object shows as Fri Aug 20 16:19:47 EDT 2021. But my responsebody shows the date via @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "America/Chicago") as 2021-08-20 14:17:43, so the two formats will not line up
I pretty much just need a Date object that has the format yyyy-MM-dd HH:mm:ss with the timezone as America/Chicago.
@stackerstack - I've updated it as per your requirement. Feel free to comment in case of any further issues/doubts.
Is there a way to update the String strDate, because it should be a new Date() that gets passed in, not a hard coded pre-formatted String date that is passed
@stackerstack - A java.util.Date object simply represents an instant on the timeline — a wrapper around the number of milliseconds since the UNIX epoch (January 1, 1970, 00:00:00 GMT); it does not have any timezone or format.
|
0

you could be missing date deserializer

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)

3 Comments

What would this do? I thought I was just trying to format the JUnit Date object, not the responsebody date object
what are you trying to test in your JUnit test?
I'm trying to match the response body so it passes via mockito
0

Posting this to only try and satisfy what you're trying to achieve. But you should follow @Arvind's answer:

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.TimeZone;


SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
String formattedDate = sdf.format(new Date());

// Updated the lines below
LocalDateTime localDateTime = LocalDateTime.parse(formattedDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Date date = Date.from(localDateTime.atZone(ZoneId.of("America/Chicago")).toInstant());

Comments

0

Best is if you can skip the Date class completely and in your response use Instant or ZonedDateTime from java.time, the modern Java date and time API.

If you cannot avoid using the outdated Date class

… I was wondering if there was a more simple way to make a Date object that would match the format of @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "America/Chicago")

Essential edit: It depends very much on what you mean by match the format. A Date can neither have a format nor a time zone. The string in your JSON has got the format mentioned. The Date has not since this would no be possible. The time zone, America/Chicago, is not present neither in JSON nor in the Date. It is only used for converting between the two. Two Date objects are equal if they denote the same point in time, there is nothing more to it. When you ask about formatting the Date to match the @JsonFormat, this necessarily means formatting into a string.

To convert a string like 2021-08-20 14:23:44 into an old-fashioned Date object I would first define the format and time zone statically:

private static final DateTimeFormatter FORMATTER
        = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ROOT);
private static final ZoneId ZONE = ZoneId.of("America/Chicago");

And then do:

    String responseDateString = "2021-08-20 14:23:44";

    Instant inst = LocalDateTime.parse(responseDateString, FORMATTER)
            .atZone(ZONE)
            .toInstant();
    Date oldfashionedDate = Date.from(inst);
    
    System.out.println(oldfashionedDate);

Output in my time zone is:

Fri Aug 20 21:23:44 CEST 2021

If I set my time zone to America/Chicago before running, it’s easier to see that the result is correct:

Fri Aug 20 14:23:44 CDT 2021

What went wrong in your code?

First you are correct that formatting a Date into a string only to parse it back is over-complicating things. Second you noticed that your exception came from this line:

LocalDate localDate = LocalDate.parse(formattedDate);

A LocalDate is a date without time of day. So its one-arg parse method expects only 2021-08-20 in the string, nothing more. It was complaining about the space, not because it was a space but just because there were more characters after the expected ones at all.

3 Comments

So the format for the Date from the instant is showing up as Fri Aug 20 14:23:44 CDT 2021 in JUnit, while the result from the response body will show up as 2021-08-20 14:23:44 because of the @JsonFormat. Is there just no way that these two will match and equal out because I need to do assertEquals on the two.
That’s true, @stackerstack. But the one in JSON is a string, not a Date, so they wouldn’t be equal anyway (JSON is a textual format).
@stackerstack I was in doubt, there may be a misunderstanding in your question, I don’t know. I have edited near the beginning of my answer to clear it up just in case it ever was there. Read and learn.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.