1

I have the following comparison in my Java code:

if(appointment.getEndDate().after(LocalDateTime.now()){

//do something
}

note that endDate field is a Calendar type.

Are there any issues with doing a comparison between Calendar and LocalDateTime this way, or is there a better way to do it?

java12399900
  • 1,485
  • 7
  • 26
  • 56
  • Many things to consider, but the gist of it being that it wouldn't be wise to compare two different sorts of time units. I prefer LocalDateTime to work with. Here's a link to convert, if you can't get rid of the Calendar. https://www.javaprogramto.com/2020/08/how-to-convert-calendar-to-localdatetime-in-java-8.html – Paul Mar 05 '21 at 12:27
  • I recommend that you neither use `Calendar` nor `LocalDateTime` for this. For a point in time that you can compare to another point in time use `Instant` or another class that defines a point in time. `LocalDateTime` does not. And the `Calendar` class is poorly designed and long outdated. – Ole V.V. Mar 05 '21 at 15:16

2 Answers2

4

Are there any issues with doing a comparison between Calendar and LocalDateTime this way, or is there a better way to do it?

Yes, it will give you an incorrect result. Moreover, 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*.

You should convert the Calendar object into Instant and then you can do the rest of the things using the modern date-time API.

Demo:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

public class Main {
    public static void main(String[] args) throws ParseException {
        // A sample calendar object
        String strDateTime = "10/02/2021 22:25";
        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm", Locale.ENGLISH);
        Date date = sdf.parse(strDateTime);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        Instant instant = calendar.getTime().toInstant();

        // Change the ZoneId as per your requirement e.g. ZoneId.of("Europe/London")
        ZoneId zoneId = ZoneId.systemDefault();

        ZonedDateTime zdt = instant.atZone(zoneId);

        ZonedDateTime now = ZonedDateTime.now(zoneId);

        System.out.println(zdt.isAfter(now));
    }
}

Output:

true

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


Update

Thanks, Ole V.V. for your valuable feedback:.

If the OP cannot afford to upgrade the appointment class to return a modern type (like ZonedDateTime) for end date-time, this is the way to go. Calendar too has a toInstant method, so you can do with simply Instant instant = calendar.toInstant();. For creating a sample old-fashioned Calendar I would use like GregorianCalendar.from(ZonedDateTime.of(2021, 10, 2, 22, 25, 0, 0, ZoneId.systemDefault()))


* 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
  • 1
    If the OP cannot afford to upgrade the appointment class to return a modern type (like `ZonedDateTime`) for end date-time, this is the way to go. `Calendar` too has a [`toInstant` method](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html#toInstant()), so you can do with simply `Instant instant = calendar.toInstant();`. For creating a sample old-fashioned `Calendar` I would use like `GregorianCalendar.from(ZonedDateTime.of(2021, 10, 2, 22, 25, 0, 0, ZoneId.systemDefault()))`. – Ole V.V. Mar 05 '21 at 19:57
3

You should not compare a Calendar with a LocalDateTime object. As per the documentation, this wil always return false

Returns whether this Calendar represents a time after the time represented by the specified Object. This method is equivalent to:

compareTo(when) > 0

if and only if when is a Calendar instance. Otherwise, the method returns false.

You need to convert your Calendar to a LocalDateTime before comparing it with another LocalDateTime

You can do a conversion with the following code

LocalDateTime localDateTime = LocalDateTime.ofInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());
Yoni
  • 1,370
  • 7
  • 17
  • [The implementation](https://github.com/openjdk/jdk/blob/f5b2f089124d3934779a7db1a2874e01afb7ef3e/src/java.base/share/classes/java/util/Calendar.java#L2796) supports that documentation; it checks `instanceof Calendar`. – Joe Apr 14 '21 at 12:59