0

I am using the following codes to do the integration testing for repository functions. However, it will fail because of the date formart. The output from SimpleDateFormat is 'Wed Jan 01 10:10:10 MST 2020', but the date from database is '2020-01-01 10:10:10.0'. Is their any easy way to handle this issue?

      Optional<TestBean> testBean = testBeanRepository.findById(1L);
      TestBean toReturn = new TestBean();
      toReturn.setAccountNumber(123456789);
      toReturn.setId(1L);
      toReturn.setCustomerName("Peter");
      toReturn.setModifiedDate(new SimpleDateFormat("yyyy-mm-dd HH:mm:ss").parse("2020-01-01 10:10:10"));
      assertThat(testBean)
         .isPresent()
         .hasValue(toReturn);

This is how I defined modified date(java.util.date):

@Column(name = "MODIFIED_DATE_TIME") 
@NotNull 
@Temporal(TemporalType.TIMESTAMP) 
private Date modifiedDate;
PLee
  • 393
  • 9
  • 26
  • Change your format to match the database, perhaps? Can you elaborate on how you attempted to solve the problem, it's not clear from your code where your attempt is. – Roddy of the Frozen Peas Feb 12 '20 at 00:03
  • I recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use for example `LocalDateTime` and `DateTimeFormatter`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Feb 12 '20 at 05:32
  • Detail, I’d prefer `assertThat(testBean).isEqualTo(Optional.of(toReturn))`. Seems simpler to me, and will give you a very nice error message no matter if the result contains a wrong value, is empty or even null. – Ole V.V. Feb 12 '20 at 05:34
  • What type is `setModifiedDate()` declared to accept? `java.util.Date`? Can you change it to modern type? `Instant` is probably appropriate, depending on exact requirements. – Ole V.V. Feb 12 '20 at 05:36
  • @OleV.V. Yes. I am using ```java.util.Date```. And ```@Column(name = "MODIFIED_DATE_TIME") @NotNull @Temporal(TemporalType.TIMESTAMP) private Date modifiedDate;``` – PLee Feb 12 '20 at 20:47

2 Answers2

1

It would seem to me that TestBean is declared to hold a java.util.Date, but the TestBean instance returned from findById() instead holds a java.sql.Timestamp. It’s very unfortunate (if it’s true).

Timestamp is implemented as a subclass of Date. Both classes are poorly designed and long outdated, we should not use them anymore. In spite of the subclass relationship, accordindg to the documentation we should not regard Timestamp as a kind of Date. Implementing Timestamp as a subclass of Date is a true hack. And putting a Timestamp into a Date field in your object is wrong. I also don’t think it was ever the intention that we should use Timestamp in our model beans. It was for transferring data to and from SQL database columns with datatype timestamp and timestamp with time zone only.

So the good solution is: Change your TestBean class to hold a modern date-time object belonging to a class of java.time, the modern Java date and time API. Edit: Since your datatype in MySQL is datetime, the best match in Java is LocalDateTime. A LocalDateTime is a date and time of day without time zone or UTC offset.

If you cannot change the type declared in the TestBean class, there are still a couple of possible improvements:

  • Make sure the object holds a Date object as it’s declared to do, not a Timestamp.
  • Add a getter and setter that return and accept an Instant rather than a Date so that your class can better interoperate with code using java.time. The new methods would do the necessary conversion. Then use the new setter for setting the value in toReturn.

If you can’t do any of this either and you’re forced to being part of the hack, there are of course ways to set modifiedDate to an old-fashioned Timestamp. I suggest:

    toReturn.setModifiedDate(Timestamp.from(Instant.parse("2020-01-01T17:10:10Z")));

I have given the time as 17:10:10. This time is in UTC (denoted by the Z). I assumed that the MST mentioned in your question is North American Mountain Standard Time (not Malaysian Standard Time?), and if so, this time corresponds to the desired 10:10:10 in your time zone.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Thanks for your reply. I am using java.util.date, and I am using temporal in the field declaration. How should I change it? I have updated my question. – PLee Feb 12 '20 at 21:25
  • It depends on your JPA implementation and version, your database engine and the datatype of the `MODIFIED_DATE_TIME` column in the database. Maybe you can simply declare the field for example `OffsetDateTime` or `Instant` (whether you still need the `@Temporal` annotation then, I don’t know). – Ole V.V. Feb 13 '20 at 03:46
  • I am using MySQL, and datatype of the date is DATETIME. – PLee Feb 13 '20 at 05:18
  • Then try `LocalDateTime` in Java, it’s the best match for MySQL `datetime`. – Ole V.V. Feb 13 '20 at 05:22
0

What you are doing is Parsing(String to Date), you need to Format(Date to String).

SimpleDateFormat readFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
SimpleDateFormat writeFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");

Optional<TestBean> testBean = testBeanRepository.findById(1L);
TestBean toReturn = new TestBean();
toReturn.setAccountNumber(123456789);
toReturn.setId(1L);
toReturn.setCustomerName("Peter");
toReturn.setModifiedDate(writeFormat.format(readFormat.parse("2020-01-01 10:10:10")));
assertThat(testBean)
        .isPresent()
        .hasValue(toReturn);

Here readFormat and writeFormat are same but they can be different.

BHAWANI SINGH
  • 729
  • 4
  • 8