anirvan
anirvan

Reputation: 4877

Time within a particular time interval

i'm trying to solve a seemingly simple problem, but just can't quite get my mind around it.

i have two times startTime and stopTime, which can be considered to be in the format: hh:mm:ss [24hr format].

Now given a third time - timeToTest - i need to find out if timeToTest lies between startTime and stopTime. There is no date information involved, other than just the times.

So for example - if i have startTime = '22:30:00' and stopTime = '03:30:00', then for timeToTest = '01:14:23', the test should return true.

I've tried a solution with java.util.Date by converting the times to milliseconds using getTime(), but with any interval which rolls over the 24 hr barrier, the logic fails.

I'm trying to build a solution using Java - but i believe the logic is language independent.

Upvotes: 3

Views: 6296

Answers (6)

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79075

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

Also, quoted below is a notice from the home page of Joda-Time:

Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.

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

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class Main {
    public static void main(String[] args) {
        String strStartTime = "22:30:00", strStopTime = "03:30:00", strTestTime = "01:14:23";
        LocalDate today = LocalDate.now();

        LocalDateTime startTime = today.atTime(LocalTime.parse(strStartTime));

        LocalDateTime stopTime = today.atTime(LocalTime.parse(strStopTime));
        if (stopTime.isBefore(startTime))
            stopTime = stopTime.plusDays(1);

        LocalDateTime testTime = today.atTime(LocalTime.parse(strTestTime));
        if (testTime.isBefore(startTime))
            testTime = testTime.plusDays(1);

        if (!testTime.isBefore(startTime) && !testTime.isAfter(stopTime))
            System.out.println(strTestTime + " is at or after " + strStartTime + " and is before or at " + strStopTime);
    }
}

Output:

01:14:23 is at or after 22:30:00 and is before or at 03:30:00

ONLINE DEMO

Note: If the start time and stop time are not inclusive, change the condition as follows:

if (testTime.isAfter(startTime) && testTime.isBefore(stopTime))
    System.out.println(strTestTime + " is after " + strStartTime + " and is before " + strStopTime);

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.

Upvotes: 2

user639466
user639466

Reputation: 103

anirvan's solution using JodaTime :

public class TimeInterval24H {
    private final LocalTime start;
    private final LocalTime end;

    public TimeInterval24H(LocalTime start, LocalTime end) {
        this.start = start;
        this.end = end;
    }

    public TimeInterval24H(Date start, Date end) {
        this(new LocalTime(start), new LocalTime(end));
    }

    public boolean contains(Date test) {
        return contains(new LocalTime(test));
    }

    public boolean contains(LocalTime test) {
        if (isAccrossTwoDays()) {
            return (test.isAfter(getStart()) || test.isBefore(getEnd()));
        } else {
            return (test.isAfter(getStart()) && test.isBefore(getEnd()));
        }
    }

    boolean isAccrossTwoDays() {
        return getEnd().isBefore(getStart());
    }

    public LocalTime getStart() {
        return start;
    }

    public LocalTime getEnd() {
        return end;
    }

}

Upvotes: 2

Evi Song
Evi Song

Reputation: 882

I strongly recommend java.util.Calendar, the before() and after() can be useful. However, you'll need a date like 5/18/2011 specified together with your time. Is it possible to specify a mock date (or a pair of date in your case) to leverage the Calendar?

Upvotes: 0

anirvan
anirvan

Reputation: 4877

So the simplest solution i could come up with, sticking to plain old java.util.Date, is shown below:

    String d1 = "21:00:00";
    String d2 = "04:00:00";
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    String dToTest = "16:00:00";
    boolean isSplit = false, isWithin = false;

    Date dt1 = null, dt2 = null,  dt3 = null;

    dt1 = sdf.parse(d1);
    dt2 = sdf.parse(d2);
    dt3 = sdf.parse(dToTest);

    isSplit = (dt2.compareTo(dt1) < 0);
    System.out.println("[split]: " +isSplit);

    if (isSplit)
    {
        isWithin = (dt3.after(dt1) || dt3.before(dt2));
    }
    else
    {
        isWithin = (dt3.after(dt1) && dt3.before(dt2));
    }

    System.out.println("Is time within interval? " +isWithin);

feel free to point out any mistakes - would love to work and fix it.

Upvotes: 5

Jon Skeet
Jon Skeet

Reputation: 1500425

How about:

  • Find the next occurrence of the specified time after the start instant
  • Check whether that occurrence is before the end instant or not

The first step can probably be broken down pretty easily:

  • Is the specified time on/after the time of the start instant?
    • Yes: the next occurrence is that time on the same day as the start instant
    • No: the next occurrence is that time on the next day from the start instant

All of this is likely to be somewhat easier to write in Joda Time than using java.util.*, by the way :)

Upvotes: 1

Aaron Digulla
Aaron Digulla

Reputation: 328594

You must add a "day" where "0" == current day, "1" == next day and so on. So in fact when stopTime == '03:30:00' it should be '27:30:00' (i.e. on the next day).

In your case, if the stopTime < startTime, then add 86400 seconds.

Upvotes: 2

Related Questions