0

I am trying to compare the response from database and web services.

response from web services is : 2020-01-07T17:15:00-08:00
response from database is :     2020-01-08 01:15:00.0

How to convert both of them to a common format?

Or is there a way to use substring to match an compare?

halfer
  • 19,824
  • 17
  • 99
  • 186

3 Answers3

1

These strings represent certain formats. Comparing them would be the equivalent of asking 'are these formats the same' – they aren't, and that's not what you want to test (you want to test: Do these strings that are in different formats nevertheless represent the same moment in time).

So, do that then. First, convert these strings (which are things for humans) into actual proper time objects, and then compare THOSE.

You can turn these strings into an Instant, which represents moments in time, and presumably what you're looking for here, and then once you have converted both to an instant, you can compare the two instants.

To turn strings into an Instant, use DateTimeFormatter. More info: java time API.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
1

We don’t know. The strings don’t give the same information, so the information from them is not readily comparable. If you know which time zone is assumed in the second string, we convert each to a point in time and compare them.

The former string is the easier one since in addition to date and time of day it also informs us of an offset from UTC (a time zone offset). So with this string we can identify a point in time. Furthermore the string is in ISO 8601 format. The classes of java.time, the modern Java date and time API, parse ISO 8601 format (or the most common variants of it) as their default that is, without any explicit formatter.

    String responseFromWs = "2020-01-07T17:15:00-08:00";
    OffsetDateTime odtFromWs = OffsetDateTime.parse(responseFromWs);
    System.out.println(odtFromWs);

Output this far is:

2020-01-07T17:15-08:00

It looks very much like the input (only the 00 seconds have been omitted). This is because OffsetDateTime also prints ISO 8601 format back (and the seconds are optional according to that format). The important thing is we’ve got a date-time object that we can use for further processing, like comparing to other date-time objects.

The trouble with the second string, the one from the database, is we don’t know the implied offset. Common recommendations include storing date and time in UTC in your database and also not to fetch it as a string from the database but as a proper date-time object, for example an OFfsetDateTime like the one we used before.

If you know that the string is in UTC and we rely on the string for now:

    DateTimeFormatter dbFormatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral(' ')
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .toFormatter();

    String responseFromDatabase = "2020-01-08 01:15:00.0";

    OffsetDateTime odtFromDb = LocalDateTime
            .parse(responseFromDatabase, dbFormatter)
            .atOffset(ZoneOffset.UTC);
    System.out.println(odtFromDb);
2020-01-08T01:15Z

Now we have got two OffsetDateTime objects. They have got methods for comparison:

    System.out.println("Before: " + odtFromWs.isBefore(odtFromDb));
    System.out.println("After: " + odtFromWs.isAfter(odtFromDb));
    System.out.println("Same time: " + odtFromWs.isEqual(odtFromDb));
    System.out.println("Equal: " + odtFromWs.equals(odtFromDb));
Before: false
After: false
Same time: true
Equal: false

You may be surprised that isEqual() returns true and equals() false. This is because isEqual() tests whether the two objects denote the same point in time, which they do, while equals() requires the same point in time and the same offset before it yields true. Since the two objects have different offsets, it returns false in this case.

Your JDBC driver or JPA implementation will probably be happy to fetch a date-time object from the database rather than the string, which, as I said, is recommended. The details depend on the datatype used in the database, but you can read more in my answer to a different questions, see the link at the bottom.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

You can convert the time stamp to equivalent date formats. The web service appears to be ISO, so you can convert the database time stamp to ISO and then finally parse the text to produce a Date, which you can use to compare.

For example:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class CompareTimeStamp {

    private String webServiceTS = ": 2020-01-07T17:15:00-08:00".replace(": ", "");
    private String dataBaseTS = ": 2020-01-08 01:15:00.0".replace(": ", "");
    private DateTimeFormatter isoFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
    private DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");

    public static void main(String[] args) {
        CompareTimeStamp cts = new CompareTimeStamp();
        LocalDateTime webServiceTime = LocalDateTime.parse(cts.webServiceTS, cts.isoFormat);
        LocalDateTime dataBaseTime = LocalDateTime.parse(cts.dataBaseTS, cts.format);
        /** OPTION 1 -Remove below code if not choosing this option*/
        System.out.println("webServiceTime: " + webServiceTime);
        System.out.println("dataBaseTime: " + dataBaseTime);
        System.out.println(cts.compareTimeStamps(webServiceTime, dataBaseTime) + "\n");
        /*********************************************************************/

        /** OPTION 2 -Remove below code if not choosing this option*/
        String webServiceTS = cts.formatTimeStamp(webServiceTime);
        String dataBaseTS = cts.formatTimeStamp(dataBaseTime);
        System.out.println("webServiceTS: " + webServiceTS);
        System.out.println("dataBaseTS: " + dataBaseTS);
        System.out.println(cts.compareTimeStamps(webServiceTS, dataBaseTS));
        /*********************************************************************/
    }

    // OPTION 1 - Compares this LocalDateTime with another ensuring that the date-time is the same.
    private String compareTimeStamps(LocalDateTime webServiceTime, LocalDateTime dataBaseTime) {
        if (webServiceTime.equals(dataBaseTime)) {
            return "Time stamp matches";
        } else {
            return "Time stamp does not match";
        }
    }

    // OPTION 2 - Compares this string to the specified object.
    private String compareTimeStamps(String webServiceTS2, String dataBaseTS2) {
        if (webServiceTS2.equals(dataBaseTS2)) {
            return "Time stamp matches";
        } else {
            return "Time stamp does not match";
        }
    }

    private String formatTimeStamp(LocalDateTime timeStamp) {
        DateTimeFormatter formating = DateTimeFormatter.ofPattern("EEEE, MMM d, yyyy HH:mm:ss a");
        String localTimeStamp = formating.format(timeStamp);
        return localTimeStamp;
    }
}

outputs:

webServiceTime: 2020-01-07T17:15
dataBaseTime: 2020-01-08T01:15
Time stamp does not match

webServiceTS: Tuesday, Jan 7, 2020 17:15:00 PM
dataBaseTS: Wednesday, Jan 8, 2020 01:15:00 AM
Time stamp does not match

modifying the time stamps:

": 2020-01-07T17:15:00-08:00"
": 2020-01-07 17:15:00.0"

outputs:

webServiceTime: 2020-01-07T17:15
dataBaseTime: 2020-01-07T17:15
Time stamp matches

webServiceTS: Tuesday, Jan 7, 2020 17:15:00 PM
dataBaseTS: Tuesday, Jan 7, 2020 17:15:00 PM
Time stamp matches
  • I am getting the first output. How to modify it later ? Using.replace function is not working i guess. – Yadullah Haider Jan 08 '20 at 16:13
  • 1
    @YadullahHaider I have updated the example to provide two options to choose from, note the comments added above. I agree with Ole V.V and have converted SimpleDateFormat to the newer DateTimeFormatter. Your comment "How to modify it later ? Using.replace function is not working i guess." Could you provide the line in the code that you are referring to? –  Jan 13 '20 at 01:19
  • Your edit is a fine improvement, thanks. I’d still clearly prefer to compare the `LocalDateTime` or other date-time objects rather than comparing strings. The latter is a bit like `String.valueOf(42).equals(String.valueOf(42))`, that is, doing extra work with no gain. Also I’d avoid the `Timestamp` class competely. It’s poorly designed (a true hack. really) and long outdated, and again, converting to `Timestamp` and back is doing extra work with no gain. – Ole V.V. Jan 13 '20 at 07:20
  • 1
    @OleV.V. Thanks. I didn't know this about Timestamp. While refactoring my code I took your advice removed it. I still like providing the O.P the two options and letting them decide. –  Jan 13 '20 at 16:34