1

I have two dates from different time zones:

String s1 = "2021-08-07T03:00:01-07:00";
String s2 = "2021-08-07T15:30:00+05:30";

I want to compare both dates. I am parsing dates like below:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss-hh:mm");
Date d = null;
try {
    d = sdf.parse(s1);
} catch (ParseException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
System.out.println(d);

How do I add time zone to the date with the zone offset provided in the string?

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
user1887464
  • 533
  • 2
  • 6
  • 11
  • 2
    I would recommend to use [`Instant::parse`](https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/time/Instant.html#parse(java.lang.CharSequence)). For one, it uses the new `java.time` API. For another, `Instant` automatically takes care of timezones. – Turing85 Aug 01 '21 at 08:05
  • 1
    The reason the your code is currently failing is that the pattern is incorrect. – Stephen C Aug 01 '21 at 08:06
  • @Turing85 `OffsetDateTime` for these particular inputs, not `Instant`. – Basil Bourque Aug 01 '21 at 08:14
  • 1
    @StephenC That, and because `SimpleDateFormat` is so troublesome. We should never use it. (The modern `DateTimeFormatter` would fail too, but with an exception telling us that something was wrong, which is already a step forward.) – Ole V.V. Aug 01 '21 at 08:15
  • @BasilBourque On one hand `Instant.parse()` does work for these inputs with newer Java versions (11+?). On the other hand using it of course means throwing away the offset information, which we may at some point want to have for other purposes, which is an argument for using `OffsetDateTime` from the outset as you said. – Ole V.V. Aug 02 '21 at 03:30

3 Answers3

3

tl;dr

OffsetDateTime
.parse( "2021-08-07T03:00:01-07:00" )
.isBefore(
    OffsetDateTime.parse( "2021-08-07T15:30:00+05:30" )
)

See this code run live at IdeOne.com.

false

Details

As commented, your formatting pattern fails to match your data. You are not using correct codes for the offset-from-UTC at the end. That is not a time-of-day with the plus and minus signs.

Never use those terrible obsolete date-time classes. They were years ago supplanted by the modern java.time classes.

Your ISO 8601 standard inputs can be parsed by default using the OffsetDateTime classes. No need to define a formatting pattern.

String s1="2021-08-07T03:00:01-07:00";
String s2="2021-08-07T15:30:00+05:30";
OffsetDateTime odt1 = OffsetDateTime.parse( s1 ) ;
OffsetDateTime odt2 = OffsetDateTime.parse( s2 ) ;
boolean odt1IsEarlier = odt1.isBefore( odt2 ) ;

See this code run live at IdeOne.com.

You may choose to adjust both objects to UTC, having an offset of zero hours-minutes-seconds. Merely extract an Instant.

Instant i1 = odt1.toInstant() ;
Instant i2 = odt2.toInstant() ;
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • so before comparing them we should bring them in the same time zone right ? how do I bring them in UTC and then we can compare them ? – user1887464 Aug 01 '21 at 09:22
  • @user1887464 (a) The `-07:00` and `+05:30` are offset-from-UTC values, *not* time zones. A time zone is a named history of the past, present, and future changes to the offset used by the people of a particular region as decided by their politicians. (b) No need to adjust. The `OffsetDateTime` class knows how to compare its objects whose offsets differ. – Basil Bourque Aug 01 '21 at 22:58
3

As others have pointed out, avoid using legacy date-time classes (Date & SimpleDateFormat) that were supplanted by the java.time classes.

If you still wish to use Date & SimpleDateFormat, read on.

Try -

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public static void main(String[] args) {
    String inputDateString1 = "2021-08-07T03:00:01-07:00";
    String inputDateString2 = "2021-08-07T15:30:00+05:30";
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
    Date d1 = null, d2 = null;
    try {
        d1 = sdf.parse(inputDateString1);
        d2 = sdf.parse(inputDateString2);
        System.out.println("Date 1 = " + d1);
        System.out.println("Date 2 = " + d2);
        System.out.println("Date 1 - Date 2 in milliseconds = " + (d1.getTime() - d2.getTime()));
    } catch (ParseException e) {
        e.printStackTrace();
    }
}

The output of the above code snippet is :-

Date 1 = Sat Aug 07 15:30:01 IST 2021
Date 2 = Sat Aug 07 15:30:00 IST 2021
Date 1 - Date 2 in milliseconds = 1000
Dhruv Saraswat
  • 858
  • 9
  • 13
  • thanks a ton. Thanks for giving example in old date apis. Wish I could give you both chosen answer – user1887464 Aug 01 '21 at 09:33
  • can you tell me how I can convert 1st date to 2nd date ? I mean applying the time zone ? converting date in 1 time to another time zone – user1887464 Oct 30 '21 at 07:37
2

The answer by Basil Bourque is correct and the recommended solution. You can use this answer as a supplement to his answer.

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*.

Solution using java.time, the modern Date-Time API:

The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards. Both of your Date-Time strings conform to the ISO 8601 format for Date-Time with timezone offset and therefore it makes perfect sense to parse them directly using OffsetDateTime. However, Java SE 12 onwards, you can parse them directly to even Instant.

Demo:

import java.time.Instant;

public class Main {
    public static void main(String[] args) {
        String s1 = "2021-08-07T03:00:01-07:00";
        String s2 = "2021-08-07T15:30:00+05:30";

        Instant instant1 = Instant.parse(s1);
        Instant instant2 = Instant.parse(s2);

        System.out.println(s1 + " represents " + instant1);
        System.out.println(s1 + " represents " + instant2);

        if (instant1.isBefore(instant2)) {
            System.out.println(s1 + " is before " + s2);
        } else if (instant1.isAfter(instant2)) {
            System.out.println(s1 + " is after " + s2);
        } else {
            System.out.println("The strings represent the same instants.");
        }
    }
}

Output:

2021-08-07T03:00:01-07:00 represents 2021-08-07T10:00:01Z
2021-08-07T03:00:01-07:00 represents 2021-08-07T10:00:00Z
2021-08-07T03:00:01-07:00 is after 2021-08-07T15:30:00+05:30

ONLINE DEMO

An Instant represents an instantaneous point on the timeline, normally represented in UTC time. The Z in the output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).

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.

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