LocalTime() разница между двумя временами

У меня есть программа маршрута полета, где мне нужно получить разницу между временем отправления и прибытия. Я получаю это указанное время как строку из данных. Вот моя проблема:

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

Это 3 рейса, которые доставят нас из EDI в SYD. Выходные данные имеют следующий формат (город, время отправления, номер рейса, пункт назначения, время прибытия).


person Naeem Khan    schedule 12.11.2018    source источник
comment
Вы знаете, проблема со временем — это всего лишь период с полуночи до полуночи, у него нет понятия о том, что существует за этими границами. Вместо этого вы должны использовать LocalDateTime, который позволяет переходить от одного дня к другому.   -  person MadProgrammer    schedule 12.11.2018
comment
Хотя ваш пример, вероятно, довольно прост, я бы порекомендовал взглянуть на ZonedDateTime, так как вы можете перемещаться между разными часовыми поясами, делая вычисления довольно ... странными: P (нередко прибываете до того, как вы уехали ????)   -  person MadProgrammer    schedule 12.11.2018
comment
Я не вижу проблемы. Результаты, которые вы получаете, являются правильными. Почему разница между 09:05 и 14:35 должна составлять 19 часов?   -  person dorony    schedule 12.11.2018
comment
@dorony Извините, я допустил ошибку и забыл изменить свой код перед публикацией. Разница должна быть от 14:35 до 09:05. В этом случае, как упомянул MadProgrammer, дата меняется, поэтому значения теряются или что-то в этом роде. Я попробовал предложение, предложенное MadProgrammer, но LocalDateTime работает только в том случае, если я укажу дату с ним (по крайней мере, насколько я проверял это прямо сейчас). Данные, которые я получаю, не предоставляют мне дату, это просто два раза. Даты не имеют значения.   -  person Naeem Khan    schedule 12.11.2018
comment
@MadProgrammer Летающий конкорд Лондон-Нью-Йорк заставит вас прибыть раньше, чем вы улетите. Так что проблема существовала и, возможно, снова возникнет в будущем...   -  person JoSSte    schedule 12.11.2018
comment
Если полученный результат ниже нуля, суммируйте его с 24 * 60, и вы получите правильный результат.   -  person dorony    schedule 12.11.2018
comment
@JoSSte Никогда не говорил, что его не существует, что я и имел в виду;)   -  person MadProgrammer    schedule 12.11.2018
comment
@dorony За исключением того, что на самом деле в сутках не 24 часа - базовая математика никогда не должна применяться к значениям даты / времени - у вас есть целый API, предназначенный для решения проблемы, лучше использовать его   -  person MadProgrammer    schedule 12.11.2018
comment
@NaeemKhan Формат выходных данных выше (город, время отправления, номер рейса, пункт назначения, время прибытия) — на основе какой даты привязки?   -  person MadProgrammer    schedule 12.11.2018
comment
В Javadoc для метода between ясен следующий вопрос: количество времени между темпоральными1Inclusive и темпоральными2Exclusive с точки зрения этой единицы; положительна, если временное значение2Exclusive позже, чем временное значение1Inclusive, отрицательно, если раньше. Вы можете захотеть, чтобы на выходе было 19 часов, но на самом деле это 5 часов с отрицательным значением, как и должно быть. (А 24 - 5 это 19....)   -  person Erwin Bolwidt    schedule 12.11.2018
comment
Имеет ли смысл 176 как продолжительность первого полета в минутах? Я бы предположил, что время 1139 и 1435 — это местное время в Эдинбурге и Стамбуле, и они не находятся в одном и том же часовом поясе, поэтому их время нельзя сравнивать таким образом. 19 часов, или, скорее, 18 часов 29 минут, правильно для времени ожидания в Стамбуле, поскольку и 14:35, и 09:06 находятся в одном и том же часовом поясе (при условии, что летнее время (DST) не начинается и не заканчивается в эту ночь).   -  person Ole V.V.    schedule 12.11.2018


Ответы (2)


Общее количество минут в 24 часа равно 1440. Поэтому, когда разница ниже нуля (а вам нужна положительная), то вам следует добавить к вашему результату целые сутки:

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

Вы можете добиться того же, используя это:

int diff = (MINUTES.between(arrival, a) + 1440) % 1440;
person ETO    schedule 12.11.2018
comment
Большое спасибо! Это исправило это. Не могли бы вы объяснить, как это работает? - person Naeem Khan; 12.11.2018
comment
@NaeemKhan Рад, что это помогло. Проверьте обновления. Если вам нужно более подробное объяснение, прочитайте о modular addition/substraction. - person ETO; 12.11.2018
comment
Я понимаю эту часть. В ту ночь мне было 5 утра, поэтому мой мозг не функционировал должным образом. Я не знал, что 1440 — это количество минут в сутках. Спасибо за объяснение. - person Naeem Khan; 13.11.2018

Основная проблема заключается в том, что 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 нет полетов :/) ... и не надо. чтобы я начал с летнего времени...

API даты/времени Java позаботится обо всем этом за нас.

Я решил сохранить информацию о дате/времени в единой единице работы, то есть в формате UTC, что позволяет всем значениям иметь какое-то полезное значение. Вы можете легко использовать другое время привязки, а также преобразовать его в другой часовой пояс для использования в презентации, чтобы вы могли отображать время по местному времени в пункте назначения, но расчеты по-прежнему выполнялись бы относительно одной точки истины.

person MadProgrammer    schedule 12.11.2018
comment
если быть придирчивым, основная проблема, ИМХО, в том, что у нас нет информации о дате во входных данных - логически, предполагая обычные рейсы, если время прибытия раньше времени вылета, мы можем предположить, что оно должно быть на один день позже... но если это путешествие на корабле, это может быть на пару дней позже... (большинство планов полета {я знаю} имеют что-то вроде +1, чтобы указать, что это на следующий день) - person user85421; 12.11.2018
comment
@CarlosHeuberger Мое предпочтительное решение будет иметь значения с датой и временем в одном часовом поясе, так что вы не столкнетесь с большой странностью, но все же физически возможно прибыть до того, как вы уйдете, даже в этом сценарии. Что я пытаюсь сделать, так это заставить людей прекратить выполнять математические манипуляции со значениями даты/времени, так как это еще хуже (ИМО) - person MadProgrammer; 12.11.2018
comment
Я рассмотрю реализацию этого в своей программе, когда она будет закончена, а сейчас мне нужно сосредоточиться на ее завершении. Спасибо вам большое за это! - person Naeem Khan; 14.11.2018