两个时间之间的LocalTime()差异

11

我有一个航班行程计划程序,需要获取出发时间和到达时间之间的差距。我从数据中获取这些指定的时间,以字符串的形式呈现。以下是我的问题:

import static java.time.temporal.ChronoUnit.MINUTES;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class test2 {
public static void main(String[] args) {

    DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("HHmm");
    LocalTime departure = LocalTime.parse("1139", dateFormat);
    LocalTime arrival = LocalTime.parse("1435", dateFormat);
    LocalTime a = LocalTime.parse("0906", dateFormat);
    System.out.println(MINUTES.between(departure, arrival));
    System.out.println(MINUTES.between(arrival, a));
}
}

输出:

176
-329

第一次计算11:39和14:35的时间差没问题。但第二次只有5个小时,实际上应该是19个小时。我该如何修复这个问题?我在这里做错了什么?

任何帮助将不胜感激。

编辑:我正在使用图形来存储我的数据。两个机场之间最短路线的示例如下:

Route for Edinburgh to Sydney
1 Edinburgh, 1139, TK3245, Istanbul, 1435
2 Istanbul, 0906, TK4557, Singapore, 1937
3 Singapore, 0804, QF1721, Sydney, 1521

以下是从EDI到SYD的三个航班,输出格式为(城市,出发时间,航班号,目的地,到达时间)。


2
你知道,时间的问题仅限于午夜AM到午夜PM这段时间,它没有超出这些边界的概念。相反,你应该使用LocalDateTime,它允许从一天过渡到另一天。 - MadProgrammer
1
虽然您的示例可能非常简单,但我建议查看ZonedDateTime,因为您可能会在不同的时区之间传递,从而使计算变得相当奇怪:P(不是没有听说过在离开之前到达) - MadProgrammer
1
我没有看到问题。你得到的结果是正确的。为什么09:05到14:35之间的时间差应该是19个小时呢? - dorony
@dorony 抱歉,我犯了一个错误,在发布之前忘记更改我的代码。差异应该是从14:35到09:05。在这种情况下,正如MadProgrammer所提到的,日期正在变化,因此值会丢失或其他原因。我尝试了MadProgrammer建议的建议,但是LocalDateTime仅在我提供日期时才起作用(至少在我目前测试它时是这样)。我得到的数据没有提供日期,只是两个时间。日期并不重要。 - Naeem Khan
2
如果您得到的结果小于零,则将其与24 * 60相加,即可获得正确的结果。 - dorony
显示剩余6条评论
2个回答

19

一天有1440分钟。所以当差值为负数时(但你需要正数),你应该将一整天加到你的结果中:

int diff = MINUTES.between(arrival, a);
if (diff < 0) {
    diff += 1440;
}

你可以使用以下方法来实现同样的效果:

int diff = (MINUTES.between(arrival, a) + 1440) % 1440;

非常感谢!这解决了问题。不过,您能否解释一下它是如何工作的呢? - Naeem Khan
@NaeemKhan 很高兴能帮到你。请查看更新内容。如果您想要更详细的解释,请阅读有关“模块加/减”的内容。 - ETO
我理解那部分。当时是凌晨5点,我的大脑没有正常运转。我没有意识到一天有1440分钟。谢谢您的解释。 - Naeem Khan

3
问题的关键在于LocalTime仅表示午夜零点到中午十二点之间的时间范围,没有超出这些范围的概念。
你真正需要的是与时间值相关联的日期值,这将允许你计算超过24小时的持续时间。
如果做不到这一点,你就需要自己“捏造”数值。这意味着,当下一个时间小于上一个时间时,你需要手动添加一个额外的周期,比如一天。
可能有几种方法可以做到这一点,这只是其中一种方法。
它需要一个设置为当前日期的ZonedDateTime作为“锚点”日期。然后将每个日程的Time应用于此日期。当它检测到最后一个到达时间早于下一个离开时间时,就会将一天添加到数值中。
import java.time.Duration;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

public class Test {

  public static void main(String[] args) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HHmm");

    List<Schedule> route = new ArrayList<>(4);
    route.add(new Schedule(LocalTime.parse("1139", formatter), LocalTime.parse("1435", formatter)));
    route.add(new Schedule(LocalTime.parse("0906", formatter), LocalTime.parse("1937", formatter)));
    route.add(new Schedule(LocalTime.parse("0804", formatter), LocalTime.parse("1521", formatter)));

    // Anchor time...
    ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("UTC"));
    ZonedDateTime lastArrival = null;
    Duration totalDuration = Duration.ZERO;
    for (Schedule schedule : route) {
      ZonedDateTime depart = zdt.with(schedule.getDepart());
      ZonedDateTime arrive = zdt.with(schedule.getArrive());

      if (lastArrival != null) {
        if (lastArrival.isAfter(depart)) {
          // Most likely, we've shifted to a new day...
          // Updat the anchor and target values
          zdt = zdt.plusDays(1);
          depart = depart.plusDays(1);
          arrive = arrive.plusDays(1);
        }
        Duration duration = Duration.between(lastArrival, depart);
        totalDuration = totalDuration.plus(duration);
        System.out.println("...Wait for " + duration.toHoursPart() + "h " + duration.toMinutesPart() + "m");
      }

      Duration duration = Duration.between(depart, arrive);
      System.out.println(duration.toHoursPart() + "h " + duration.toMinutesPart() + "m");
      totalDuration = totalDuration.plus(duration);

      lastArrival = arrive;
    }
    System.out.println("Total duration of " + totalDuration.toHoursPart() + "d " + totalDuration.toHoursPart() + "h " + totalDuration.toMinutesPart() + "m");

  }

  public static class Schedule {

    private LocalTime depart;
    private LocalTime arrive;

    public Schedule(LocalTime depart, LocalTime arrive) {
      this.depart = depart;
      this.arrive = arrive;
    }

    public LocalTime getDepart() {
      return depart;
    }

    public LocalTime getArrive() {
      return arrive;
    }

  }
}

这将输出...

2h 56m
...Wait for 18h 31m
10h 31m
...Wait for 12h 27m
7h 17m
Total duration of 3d 3h 42m

但是为什么要这样做呢?因为日期/时间处理非常混乱,有闰秒、年份和其他愚蠢的规则,旨在防止它崩溃成混乱状态(这就是为什么没有航班在12:00 :/)...而且不要让我开始谈夏令时...

Java日期/时间API为我们处理了所有这些问题。

我选择在单个工作单元中维护日期/时间信息,即UTC,这允许所有值具有某种有用的含义。您也可以轻松使用不同的锚定时间以及转换为不同的时区以供演示使用 - 因此,您可以在目标地显示本地时间,但计算将继续根据一个真实的参考点进行。


挑剔一点,主要问题是,在输入数据中我们没有日期信息——从逻辑上讲,假设正常航班,如果到达时间早于出发时间,我们可以假设它必须是第二天...但如果是船运,可能会晚几天...(我所知道的大多数航班计划都有类似于“+1”的东西,表示它是第二天)。 - user85421
@CarlosHeuberger 我“偏爱”的解决方案是将日期和时间值都放在一个单一的时区中,这样你就不会遇到太多奇怪的问题,但即使在这种情况下,到达时间早于出发时间仍然是可能的。我“试图”让人们停止对日期/时间值进行数学运算,因为这样做甚至更糟糕(在我看来)。 - MadProgrammer
当我的程序完成后,我会考虑将其实现,现在我需要专注于完成它。非常感谢你! - Naeem Khan

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