Java - разница в минутах - PullRequest
0 голосов
/ 10 марта 2020
  • Я должен посчитать разницу в минутах между этими двумя датами, но даты перекрываются.
  • У меня есть два диапазона дат: EventStart, EventEnd
  • Я написал SQL Запрос раньше (см. Ниже), и он работает отлично, но очень медленно, поэтому я хочу обработать его в Java (resultSet)

Вот JSON, который я получаю от SQL Сервера:

https://pastebin.com/raw/xhCnXynA

Вот мой SQL работающий скрипт:

DECLARE @T TABLE(ID INT,FromDate DATETIME, ToDate DATETIME)

INSERT INTO @T(ID,FromDate,ToDate)
SELECT 1,'20090801','20090803' UNION ALL
SELECT 2,'20090802','20090809' UNION ALL
SELECT 3,'20090805','20090806' UNION ALL
SELECT 4,'20090812','20090813' UNION ALL
SELECT 5,'20090811','20090812' UNION ALL
SELECT 6,'20090802','20090802'

SELECT ROW_NUMBER() OVER(ORDER BY s1.FromDate) AS ID,
       s1.FromDate,
       MIN(t1.ToDate) AS ToDate
FROM @T s1
INNER JOIN @T t1 ON s1.FromDate <= t1.ToDate
  AND NOT EXISTS(SELECT * FROM @T t2
                 WHERE t1.ToDate >= t2.FromDate
                   AND t1.ToDate < t2.ToDate)
WHERE NOT EXISTS(SELECT * FROM @T s2
                 WHERE s1.FromDate > s2.FromDate
                   AND s1.FromDate <= s2.ToDate)
GROUP BY s1.FromDate
ORDER BY s1.FromDate

Результат:

enter image description here

My Java код:

//Date Format
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");   

Integer downTime;

while (rs.next()) {  

    //Parse to Date
    eventStart = formatter.parse(rs.getString("EventStart"));
    eventEnd = formatter.parse(rs.getString("EventEnd"));

    if (eventStart.after(eventEnd)){
         //How should I do this?
    }
    else{
         //How should I do this?
    }

    //I have to count here the difference between the dates in minutes
}  

1 Ответ

3 голосов
/ 10 марта 2020

Подсчет разницы в минутах между двумя датами

Лучше использовать java.time.format.DateTimeFormatter и java.time.LocalDateTime из нового Java API даты / времени вместо SimpleDateFormat и Date:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
LocalDateTime eventStart = LocalDateTime.parse("2019-10-09 01:24:05.0", formatter);
LocalDateTime eventEnd = LocalDateTime.parse("2019-10-09 01:35:14.0", formatter);
Duration duration;
if (eventStart.isBefore(eventEnd)) {
  duration = Duration.between(eventStart, eventEnd);
} else {
  duration = Duration.between(eventEnd, eventStart);
}
long minutes = duration.toMinutes();
System.out.println("" + minutes + " minute(s)");

Результат: 11 minute(s).

Объединение всех перекрывающихся диапазонов дат

Чтобы объединить все перекрывающиеся диапазоны дат, рассмотрите следующий подход.

Создание класс для представления диапазона дат с помощью методов isOverlappingWith, mergeWith, toMinutes и переопределения equals и hashCode.

private static class DateRange {

  private final LocalDateTime startDate;
  private final LocalDateTime endDate;

  public DateRange(LocalDateTime startDate, LocalDateTime endDate) {
    this.startDate = startDate;
    this.endDate = endDate;
  }

  public boolean isOverlappingWith(DateRange other) {
    return !startDate.isAfter(other.endDate) && !endDate.isBefore(other.startDate);
  }

  public DateRange mergeWith(DateRange other) {
    return new DateRange(
        startDate.isBefore(other.startDate) ? startDate : other.startDate,
        endDate.isAfter(other.endDate) ? endDate : other.endDate);
  }

  public long toMinutes() {
    return Duration.between(startDate, endDate).toMinutes();
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    DateRange dateRange = (DateRange) o;
    return Objects.equals(startDate, dateRange.startDate) &&
        Objects.equals(endDate, dateRange.endDate);
  }

  @Override
  public int hashCode() {
    return Objects.hash(startDate, endDate);
  }

  @Override
  public String toString() {
    return "DateRange{" +
        "startDate=" + startDate +
        ", endDate=" + endDate +
        '}';
  }
}

Выполните итерацию по всем диапазонам дат и попытайтесь объединить их. Для отслеживания дубликатов требуется дополнительно HashSet. Идея состоит в том, чтобы попытаться объединить каждый диапазон дат со следующими диапазонами в списке. Если произошло хотя бы одно слияние, удалите исходный диапазон дат. Если в списке нет результирующего диапазона дат слияния, добавьте его в список.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");

List<List<String>> rawDateRanges = List.of(
    List.of("2009-08-01 00:00:00.0", "2009-08-03 00:00:00.0"),
    List.of("2009-08-05 00:00:00.0", "2009-08-06 00:00:00.0"),
    List.of("2009-08-02 00:00:00.0", "2009-08-09 00:00:00.0"),
    List.of("2009-08-12 00:00:00.0", "2009-08-13 00:00:00.0"),
    List.of("2009-08-11 00:00:00.0", "2009-08-12 00:00:00.0"),
    List.of("2009-08-02 00:00:00.0", "2009-08-02 00:00:00.0"));

List<DateRange> dateRanges = new ArrayList<>();
for (List<String> rawDateRange : rawDateRanges) { //Replace with while (rs.next()) { ... }
  LocalDateTime fromDate = LocalDateTime.parse(rawDateRange.get(0), formatter);
  LocalDateTime toDate = LocalDateTime.parse(rawDateRange.get(1), formatter);
  dateRanges.add(new DateRange(fromDate, toDate));
}

Set<DateRange> mergedDateRanges = new HashSet<>();
for (int i = 0; i < dateRanges.size(); i++) {
  DateRange dateRange = dateRanges.get(i);
  boolean merged = false;
  for (int j = i + 1; j < dateRanges.size(); j++) {
    DateRange otherDateRange = dateRanges.get(j);
    if (dateRange.isOverlappingWith(otherDateRange)) {
      dateRange = dateRange.mergeWith(otherDateRange);
      merged = true;
    }
  }
  if (merged) {
    dateRanges.remove(i--);
    if (mergedDateRanges.add(dateRange)) {
      dateRanges.add(dateRange);
    }
  }
}

List<Long> minutes = dateRanges.stream()
    .peek(System.out::println)
    .map(DateRange::toMinutes) //Convert to minutes
    .collect(toList());

System.out.println(minutes);

Вывод:

DateRange{startDate=2009-08-01T00:00, endDate=2009-08-09T00:00}
DateRange{startDate=2009-08-11T00:00, endDate=2009-08-13T00:00}
[11520, 2880]
...