javaandroidandroid-calendar

How to compare two date ranges in Android?


I am currently trying to figure out how to compare the two date ranges using Calendar object in java.

For example, if the first two given dates are 2021-7-1 and 2021-7-8 and the second two given dates are 2021-7-8 and 2021-7-10, it should return false because the date ranges of the first two given dates and the second two given dates are overwritten at 2021-7-8.

Is there any possibility to figure out this using Calendar and Date objects?


Solution

  • tl;dr

    LocalDateRange a = LocalDateRange.ofClosed(
        LocalDate.parse( "2021-07-01" ) ,
        LocalDate.parse( "2021-07-08" )
    )
    .abuts(                                            // Or .overlaps or .isConnected
        LocalDateRange b = LocalDateRange.ofClosed(
            LocalDate.parse( "2021-07-08" ) ,
            LocalDate.parse( "2021-07-10" )
        )
    )
    

    Avoid legacy date-time classes

    using Calendar object

    Never use Calendar or Date. These terrible classes were supplanted years ago by the java.time classes defined in JSR 310.

    Date ranges

    if the first two given dates are 2021-7-1 and 2021-7-8 and the second two given dates are 2021-7-8 and 2021-7-10, it should return false because the date ranges of the first two given dates and the second two given dates are overwritten at 2021-7-8.

    You want to compare two date ranges.

    LocalDate

    In modern Java we use LocalDate to represent a date without a time-of-day and without the context of a time zone or offset-from-UTC.

    org.threeten.extra.LocalDateRange

    To work with date ranges (a pair of LocalDate objects), I suggest you add the ThreeTen-Extra library to your project, free-of-cost and open-source. This library includes the LocalDateRange class, just what you need.

    Half-open spans

    You should know that in date-time handling, it usually makes sense to define a span of time as Half-Open, where the beginning is inclusive while the ending is exclusive. So a full day starts at the first moment of the day and runs up to, but does not include, the first moment of the next day.

    In your case, your first range ends on the 8th, and the second range begins on the 8th. By Half-Open rules, these two ranges would abut rather than overlap.

    LocalDateRange x = LocalDateRange.of(
            LocalDate.parse( "2021-07-01" ) ,
            LocalDate.parse( "2021-07-08" )
    );
    LocalDateRange y = LocalDateRange.of(
            LocalDate.parse( "2021-07-08" ) ,
            LocalDate.parse( "2021-07-10" )
    );
    
    boolean abuts = x.abuts( y );
    boolean overlaps = x.overlaps( y );
    

    When run.

    abuts = true

    overlaps = false

    I believe making consistent use of Half-Open makes your code easier to read and reason about, and is less likely to have mistakes from an oversight.

    Fully-closed spans

    However, if you insist on the Fully-Closed approach, the LocalDateRange class lets you work that way. Use LocalDateRange.ofClosed rather than LocalDateRange.of.

    LocalDateRange a = LocalDateRange.ofClosed(
            LocalDate.parse( "2021-07-01" ) ,
            LocalDate.parse( "2021-07-08" )
    );
    LocalDateRange b = LocalDateRange.ofClosed(
            LocalDate.parse( "2021-07-08" ) ,
            LocalDate.parse( "2021-07-10" )
    );
    
    boolean abuts = a.abuts( b );
    boolean overlaps = a.overlaps( b );
    

    When run.

    abuts = false

    overlaps = true

    Using the Fully-Closed approach, your two ranges overlap rather than abut, the opposite of what we saw above in previous example code.

    Overlaps or abuts

    Be aware of the isConnected method, the equivalent to (overlaps(other) || abuts(other)). The LocalDateRange class offers other comparison methods too.


    About java.time

    The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

    To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

    The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

    You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.

    Where to obtain the java.time classes?

    Table of which java.time library to use with which version of Java or Android

    The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.