2015-01-25 3 views
3

Я ищу библиотеку или вспомогательный класс на Java, что позволило бы мне выполнять суммирование и вычитание интервала дат.Сумма и вычитание интервала времени в Java

Например, давайте скажем у меня есть следующие интервалы дат:

A = ["2015-01-01 00:00", "2015-01-20 00:00"] 
B = ["2015-01-05 00:00", "2015-01-10 00:00"] 
C = ["2015-01-11 00:00", "2015-01-14 00:00"] 
D = ["2015-01-19 00:00", "2015-01-25 00:00"] 

1     A    20 
|----------------------------------| 
    |---------| |----------| |------------| 
    5 B 10 11 C 14 19 D  25 

И давайте говорить, что я хотел бы вычислить следующее:

A - B - C + D = { ["2015-01-01 00:00", "2015-01-05 00:00"[, 
        ]"2015-01-10 00:00", "2015-01-11 00:00"[, 
        ]"2015-01-14 00:00", "2015-01-25 00:00"] } 

1 5   10 11   14    25 
|---|   |---|   |----------------| 

Я знаю, что могу строить свою собственную логику используя чистую Java, но я бы не стал изобретать колесо ...

Я искал Joda-Time, но я не мог понять, как выполнять такие операции с его помощью.

Большое спасибо!

+0

Кстати, Joda Время новый интегрирован в Java 8 в качестве новой даты/времени API. –

+0

Интересно! Но способен ли он выполнять описанные мной операции? – tiagobt

+0

Я думаю, вы имеете в виду «союз» и «пересечение», а не сумму и вычитание ... – Adam

ответ

5

Я нашел именно то, что мне нужно: Ranges, из guava-libraries.

работает так:

Range<Date> a = Range.closed(
    new GregorianCalendar(2015, 0, 1).getTime(), 
    new GregorianCalendar(2015, 0, 20).getTime()); 
Range<Date> b = Range.closed(
    new GregorianCalendar(2015, 0, 5).getTime(), 
    new GregorianCalendar(2015, 0, 10).getTime()); 
Range<Date> c = Range.closed(
    new GregorianCalendar(2015, 0, 11).getTime(), 
    new GregorianCalendar(2015, 0, 14).getTime()); 
Range<Date> d = Range.closed(
    new GregorianCalendar(2015, 0, 19).getTime(), 
    new GregorianCalendar(2015, 0, 25).getTime()); 

RangeSet<Date> result = TreeRangeSet.create(); 
result.add(a); 
result.remove(b); 
result.remove(c); 
result.add(d); 

System.out.println(result); 

код, приведенный выше принтами:

[ 
    [Thu Jan 01 00:00:00 BRST 2015‥Mon Jan 05 00:00:00 BRST 2015), 
    (Sat Jan 10 00:00:00 BRST 2015‥Sun Jan 11 00:00:00 BRST 2015), 
    (Wed Jan 14 00:00:00 BRST 2015‥Sun Jan 25 00:00:00 BRST 2015] 
] 
+0

Да, это хорошее решение, если вы все еще хотите продолжить «GregorianCalendar» и т. Д. Однако эти классы также содержат информацию о часовом поясе (не содержащуюся в вашем исходном вопросе). Другая библиотека, которая может быть интересна для вас, - это моя библиотека Time4J, особенно особенно пакет range с классом [IntervalCollection] (http://time4j.net/javadoc-en/net/time4j/range/IntervalCollection.html) –

+0

Интересные , @MenoHochschild. Я посмотрю на вашу библиотеку. Тем не менее, как «Range», так и «RangeSet» являются общими, поэтому я мог бы выбрать класс даты, который не будет содержать информацию о часовом поясе (при условии, что он реализует интерфейс «Comparable»). – tiagobt

+0

Правда, Guava также можно сочетать с классами Joda-Time или Java-8-классами, такими как «LocalDate» и т. Д. Это намного лучше, чем прямое использование Joda-Time-Interval (см. Другой ответ, связанный с Joda). О моей библиотеке я собираюсь реализовать недостающую минус() - операцию для интервалов в следующей версии (хотя возможно обходное решение). –

0

Я думаю, что это может быть сделано в основном с использованием Joda-Time с некоторым пользовательским кодом. Предполагается, что A является Интервалом, к которому должны относиться все остальные интервалы.

Хотя этот код должен давать ожидаемые результаты (и должен работать для разных значений соответственно), я настоятельно рекомендую тестировать его с очень разными данными, особенно для трех случаев: a) интервал, не пересекающий A вообще, b) пересекающийся A в начале и в) интервал, который сам пересекает B или C или D.

Поэтому, несмотря на это, это может помочь в проведении дальнейших испытаний.

Interval a = new Interval(Instant.parse("2015-01-01T00:00Z"), Instant.parse("2015-01-20T00:00Z")); 
List<Interval> l = Arrays.asList(
     /* b */ new Interval(Instant.parse("2015-01-05T00:00Z"), Instant.parse("2015-01-10T00:00Z")), 
     /* c */ new Interval(Instant.parse("2015-01-11T00:00Z"), Instant.parse("2015-01-14T00:00Z")), 
     /* d */ new Interval(Instant.parse("2015-01-19T00:00Z"), Instant.parse("2015-01-25T00:00Z")) 
); 
List<Interval> results = new ArrayList<Interval>(); 

for (Interval i : l) { 
    if (a.contains(i)) { 
     // if i is completely inside a, then calculate the first part and the remaining part 
     // whereas the first part will be added to the result 
     Interval firstPart = new Interval(a.getStart(), i.getStart()); 
     results.add(firstPart); 
     // followed by i itself (skipped) 
     // part after i, inside a 
     Interval remainingPart = new Interval(i.getEnd(), a.getEnd()); 
     a = remainingPart; 
    } else if (i.overlaps(a)) { 
     // if the intervals only overlap, then we take the earliest beginning and the latest ending as a result part 
     DateTime overlapMin = (a.getStart().isBefore(i.getStart())) ? a.getStart() : i.getStart(); 
     DateTime overlapMax = (a.getEnd().isAfter(i.getEnd())) ? a.getEnd() : i.getEnd(); 
     Interval overlapAndBothParts = new Interval(overlapMin, overlapMax); 
     results.add(overlapAndBothParts); 
     // if the checked interval i is at the beginning, then a will become the part after this "overlap" 
     if (i.getStartMillis() < a.getStartMillis()) { 
      Interval whatsLeft = new Interval(i.getEndMillis(), a.getEndMillis()); 
      a = whatsLeft; 
     } 
    } 
} 

// print result 
for (Interval i : results) { 
    System.out.println("result part: " + i); 
} 
+0

Большое спасибо за помощь @jCoder. Единственная проблема с этим решением в том, что он не позволяет мне указать, какую операцию я хочу (сумма/объединение или вычитание). Если я правильно понимаю, он выполняет вычитание в случае, если А содержит другой интервал, и он выполняет сумму/объединение в случае, если интервал перекрывает А. В любом случае, я попытаюсь написать код, который решает мою проблему на основе вашей. – tiagobt

Смежные вопросы