0

I tried reading a lot about the date formatting with time zone, but it doesn't make sense to me.

My DB shows this datetime: 2022-12-01 04:00:00.000 +08:00
My UI shows it as: Thu 01/12/2022 12:00

I need to compare between them to verify they are the same. I tried to convert the DB time like this:

String dbDate = "2022-12-01 04:00:00.000 +08:00";
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS XXX");
Date date = sf.parse(dbDate)

sf = new SimpleDateFormat("EEE dd/MM/yyy HH:mm");  
String uiDate = sf.format(date);

The results received is a completely different date: 'Wed 30/11/2022 22:02'.

I don't understand the logic here and would appreciate help in converting it correctly.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • 1
    I see multiple places where this comparison can fail: your UI doesn't have timezone, nor seconds or milliseconds, while the 2nd part is easy to overcome by saying that 2 dates are equal if they have the same time up to the minute, it's impossible to compare zoned time with a non-zoned time – Yonatan Karp-Rudin Nov 22 '22 at 12:07
  • What your UI shows is wrong. Did the sign of the offset from the database somehow get reversed? – Ole V.V. Nov 22 '22 at 14:02
  • I strongly recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use `OffsetDateTime`, `LocalDateTime` and `DateTimeFormatter`, all from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Nov 22 '22 at 15:36
  • The format that your database shows should be irrelevant. Retrieve your database `timestamp with time zone` (as I presume it is) as an `OffsetDateTime` in Java. See for example [Getting the date from a ResultSet for use with java.time classes](https://stackoverflow.com/questions/29773390/getting-the-date-from-a-resultset-for-use-with-java-time-classes). – Ole V.V. Nov 22 '22 at 15:39
  • Your UI probably makes an assumption that the use seeing the *Thu 01/12/2022 12:00* is in some specific time zone. Do you know which time zone that is? That knowledge would make it possible to compare. I would then convert the text from the UI to `OffsetDateTime` using that time zone, and I would truncate the value from the database to whole minutes and compare. – Ole V.V. Nov 22 '22 at 15:44
  • I cannot reproduce the result you are reporting, `Wed 30/11/2022 22:02`. I got `Wed 30/11/2022 21:00`. Depending on the default time zone I can get `Wed 30/11/2022 22:00` but not `:02`. – Ole V.V. Nov 22 '22 at 15:55
  • I believe that you *are* converting it correctly. The logic is: At 4 in the night at offset +08:00 (for example Asia/Ujung_Pandang time zone) it is still the previous day on most of the globe. For example it is 22:00 the previous evening in Asia/Gaza time zone (offset +02:00) and 21:00 in my time zone (offset +01:00). – Ole V.V. Nov 22 '22 at 16:18

1 Answers1

4

As already commented by Yonatan Karp-Rudin, you can not compare a date-time with time-zone offset with another without time-zone offset. A clear way to compare the two date-times is to bring them to a single time-zone e.g. you can apply the same time-zone offset to the UI date-time as of the DB date-time.

In March 2014, java.time API supplanted the error-prone legacy date-time API. Since then, it has been strongly recommended to use this modern date-time API.

Demo using java.time API:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String dt1 = "2022-12-01 04:00:00.000 +08:00";
        String dt2 = "Thu 01/12/2022 12:00";

        DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS XXX", Locale.ENGLISH);
        OffsetDateTime odt1 = OffsetDateTime.parse(dt1, dtf1);
        System.out.println(odt1);

        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("EEE dd/MM/uuuu HH:mm", Locale.ENGLISH)
                .withZone(odt1.getOffset());
        OffsetDateTime odt2 = OffsetDateTime.parse(dt2, dtf2);
        System.out.println(odt2);

        System.out.println(odt1.equals(odt2));
    }
}

Output:

2022-12-01T04:00+08:00
2022-12-01T12:00+08:00
false

Assuming both the date-times belong to the same time-zone offset, another way to compare them would be compare them without time-zone i.e. comparing their date-time part only (LocalDateTime).

Demo:

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String dt1 = "2022-12-01 04:00:00.000 +08:00";
        String dt2 = "Thu 01/12/2022 12:00";

        DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS XXX", Locale.ENGLISH);
        LocalDateTime ldt1 = OffsetDateTime.parse(dt1, dtf1).toLocalDateTime();
        System.out.println(ldt1);

        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("EEE dd/MM/uuuu HH:mm", Locale.ENGLISH);
        LocalDateTime ldt2 = LocalDateTime.parse(dt2, dtf2);
        System.out.println(ldt2);

        System.out.println(ldt1.equals(ldt2));
    }
}

Output:

2022-12-01T04:00
2022-12-01T12:00
false

The modern date-time API (java.time API) provides you with tools to do the same thing in many ways e.g. in the 1st demo, we could obtain the OffsetDateTime for your UI date-time string by parsing it into a LocalDateTime as shown in the 2nd demo and then using one of the ways shown in this answer where ZoneOffset offset = odt1.getOffset().

By the way, here is an example of how you format a date-time with time-zone offset to another format:

public class Main {
    public static void main(String[] args) {
        String dtDb = "2022-12-01 04:00:00.000 +08:00";
        DateTimeFormatter parser = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS XXX", Locale.ENGLISH);
        OffsetDateTime odtDb = OffsetDateTime.parse(dtDb, parser);
        System.out.println(odtDb);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE dd/MM/uuuu HH:mm", Locale.ENGLISH);
        String strDtUi = odtDb.format(formatter);
        System.out.println(strDtUi);
    }
}

Output:

2022-12-01T04:00+08:00
Thu 01/12/2022 04:00

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

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110