特定时间间隔内的时间

3

我试图解决一个看似简单的问题,但就是无法完全理解。

我有两个时间 startTimestopTime,可以认为它们的格式为: hh:mm:ss [24小时制]。

现在给定第三个时间 - timeToTest - 我需要找出 timeToTest 是否在 startTimestopTime 之间。除了时间以外,没有涉及任何日期信息。

例如 - 如果我有 startTime = '22:30:00'stopTime = '03:30:00',那么对于 timeToTest = '01:14:23',测试应该返回 true。

我尝试使用 java.util.Date 的解决方案,通过使用 getTime() 将时间转换为毫秒,但是在任何超过24小时的区间内,逻辑都会失败。

我正在尝试使用 Java 构建解决方案 - 但我相信这种逻辑是与语言无关的。

6个回答

4

所以,我能想到的最简单的解决方案是,坚持使用传统的java.util.Date,如下所示:

    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);

欢迎指出任何错误 - 我很乐意工作并修复它。


2

使用JodaTime的anirvan解决方案:

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;
    }

}

2

你需要添加一个“day”,其中“0”表示当前日期,“1”表示下一天,依此类推。因此,实际上当 stopTime == '03:30:00' 时,它应该是 '27:30:00'(即第二天)。

在你的情况下,如果 stopTime < startTime,则添加86400秒。


Aaron,我已经尝试了将一天添加到stopTime的方法,当它小于startTime时。然而,我面临的问题是-何时决定将一天添加到timeToTest中。例如,当timeToTest大于00:00:00但小于stopTime时,我应该将一天添加到timeToTest中。但是当它小于00:00:00时,我不应该这样做。 此外,由于我需要在数据集上运行此逻辑,我认为进行如此多的检查并创建新的日期对象可能会导致性能开销。 - anirvan
好吧,如果时间在午夜之后,那么它就是下一天了。你的问题在于“日期”信息被丢弃了,而从剩下的部分重新创建它的安全方法是不存在的。唯一安全的解决方案是在创建数据时保留这个重要的事实。 - Aaron Digulla
关于性能方面:当你的解决方案能够正常工作但是运行缓慢时,开始担心它的性能。避免过早优化。 - Aaron Digulla

2

java.time

Java.util日期时间API及其格式化API——SimpleDateFormat已经过时且容易出错。建议完全停止使用它们并切换到现代日期时间API*

此外,以下是来自Joda-Time主页的通知:

请注意,从Java SE 8开始,用户被要求迁移到java.time(JSR-310)——JDK的核心部分,该部分替换了此项目。

使用现代日期时间API——java.time的解决方案:

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);
    }
}

输出:

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

在线演示

注意:如果开始时间和结束时间不包含在内,请按以下方式更改条件:

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

了解有关现代日期时间API的更多信息,请参阅Trail: Date Time


* 如果由于任何原因,您必须坚持使用Java 6或Java 7,则可以使用ThreeTen-Backport,它将大部分java.time功能回溯到Java 6和7。如果您正在为Android项目工作,并且您的Android API级别仍不符合Java-8,请查看通过去糖化可用的Java 8+ API如何在Android项目中使用ThreeTenABP


1

怎么样:

  • 查找指定时间在开始时刻之后的下一个出现时间
  • 检查该出现时间是否在结束时刻之前

第一步可能很容易分解:

  • 指定时间在开始时刻的时间之后吗?
    • 是:下一个出现时间是当天的那个时间
    • 否:下一个出现时间是从开始时刻的下一天的那个时间

顺便说一句,使用Joda Time比使用java.util.*更容易编写所有这些内容 :)


确实,Joda Time非常好用,也许新的JSR-310 https://jsr-310.dev.java.net/实现可以解决java.util.Date存在的许多问题。 - A. Ionescu
那就是我一直在研究的逻辑。然而,像查找指定时间的下一个发生时间这样的事情,我发现很难或者说比较复杂[使用java.util.Date]。我正在研究Joda,但还没有看到能简化该任务的东西。 - anirvan
@anirvan:Joda Time使得将“LocalDateTime”、“LocalDate”和“LocalTime”的概念分离变得容易。如果您选择完整的DateTime值,事情会变得混乱,因为可能涉及到DST更改...例如,偶尔您可能会有一个晚上10点开始,第二天下午5点结束的情况-但在两者之间没有1.30am... - Jon Skeet

0
我强烈推荐使用java.util.Calendar,其中的before()和after()方法非常有用。但是,您需要指定一个日期,比如5/18/2011,并将其与您的时间一起使用。您是否可以指定一个模拟日期(或者在您的情况下一对日期),以利用Calendar呢?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接