Первый подход: только с помощью Java 6
Когда я вижу ваши примеры дат, как 2015-01-31
тогда я получаю сильное подозрение, что вы говорите о замкнутых интервалов дат иначе выбирая конец месяца может показаться немного странным. Это широко распространенный и разумный подход. К сожалению, выбор типа данных, такого как java.util.Calendar
, представляющий собой мгновенный (также комбинированный с датой и зоной времени), не согласуется с закрытыми интервалами. Подобные типа типа работают лучше с полуоткрытыми интервалами. Следствием этого является:
Если вы решили использовать только Java-6-типа, то вы можете попытаться преобразовать все Calendar
-Объекты в длинных значений, представляющих истекшее миллисекунды с момента Unix эпохи, как было предложено @guillaume Жиро-vitouchkina (имеет я получил в качестве примера пример, как это сделать без какой-либо внешней библиотеки). Но вы должны добавить дополнительный день к каждому Calendar
-объекту (если изображать конечную границу) заранее, чтобы добиться эффекта закрытых интервалов дат.
И, конечно же, вы все равно должны сделать некоторые домашние арифметические интервалы, как показано в этом ответе отрывочным способом. Если вы внимательно изучите другие предложения и свои собственные требования, вы обнаружите, что для окончательного решения требуется даже больше, чем просто новый класс интервалов или базовые сравнения интервалов. Вам также потребуется более высокий уровень абстракции, а именно определенные операции между несколькими интервалами. Это может привести к некоторой головной боли. С другой стороны: реализация арифметики с длинным интервалом может сэкономить некоторые издержки производительности как типичные для дополнительной библиотеки интервалов, если у вас хорошие навыки программирования.
Второй подход: Использование выделенного интервала библиотеки
Я знаю только четыре библиотеки, которые обещают справиться с интервалами. Threeten-Extra, упомянутый @Basil Bourque, не может быть использован, поскольку для него требуется Java-8. У его интервала класса есть недостаток, чтобы обрабатывать только моменты, но не даты календаря. Также почти нет поддержки для обработки коллекций интервалов. То же самое можно сказать и о Joda-Time (который, по крайней мере, работает на Java-6, а также предлагает специальный тип календарной даты, а именно LocalDate
, но без интервалов времени).
Интересный вариант использует Guava и его класс RangeSet, особенно если вы решите продолжить использование Calendar
-Объектов и Longs. Этот класс имеет некоторую поддержку для обработки операций между интервалами - для меня это гораздо более привлекательно, чем использование простого класса интервалов Joda-Time.
Наконец, у вас также есть возможность использовать мою библиотеку Time4J, у которой есть range-package. Я покажу вам полное решение вашей проблемы:
// our test interval
PlainDate start = PlainDate.of(2013, Month.JANUARY, 31);
PlainDate end = SystemClock.inLocalView().today();
DateInterval test = DateInterval.between(start, end);
IntervalCollection<PlainDate> icTest = IntervalCollection.onDateAxis().plus(test);
// two intervals for your GOOD case
PlainDate s1 = PlainDate.of(2013, Month.JANUARY, 31);
PlainDate e1 = PlainDate.of(2014, Month.JANUARY, 31);
DateInterval i1 = DateInterval.between(s1, e1);
PlainDate s2 = PlainDate.of(2013, Month.MAY, 31);
PlainDate e2 = end; // today
DateInterval i2 = DateInterval.between(s2, e2);
IntervalCollection<PlainDate> goodCase =
IntervalCollection.onDateAxis().plus(i1).plus(i2);
boolean covered = icTest.minus(goodCase).isEmpty();
System.out.println("Good case: " + covered); // true
// two intervals for your BAD case
PlainDate s3 = PlainDate.of(2013, Month.JANUARY, 31);
PlainDate e3 = PlainDate.of(2014, Month.JANUARY, 31);
DateInterval i3 = DateInterval.between(s3, e3);
PlainDate s4 = PlainDate.of(2014, Month.MARCH, 31);
PlainDate e4 = end; // today
DateInterval i4 = DateInterval.between(s4, e4);
IntervalCollection<PlainDate> badCase =
IntervalCollection.onDateAxis().plus(i3).plus(i4);
covered = icTest.minus(badCase).isEmpty();
System.out.println("Bad case: " + covered); // false
Самая большая часть кода - это просто интервал. Реальный интервал сама арифметика выполняется этим удивительно небольшой фрагмент кода:
boolean covered =
IntervalCollection.onDateAxis().plus(test).minus(
IntervalCollection.onDateAxis().plus(i1).plus(i2)
).isEmpty();
Объяснение: Интервал испытаний покрывается интервалами i1 и i2, если остаток от вычитания i1 и i2 из теста пуст.
К слову: интервалы времени в Time4J по умолчанию являются закрытыми интервалами. Вы можете изменить эти интервалы на половину открытых интервалов, но если вы действительно хотите (просто позвонив withOpenEnd()
с заданным интервалом дат).
И если вы планируете перейти на Java-8 позже, вы можете просто обновить версию Time4J до версии 4.x (версия v3.x для Java-6) и получить очень легкие преобразования в Java-8 типа java.time.LocalDate
(например: PlainDate.from(localDate)
или LocalDate ld = plainDate.toTemporalAccessor()
), поэтому вы можете продолжать использовать Time4J для дополнительных функций, не охватываемых стандартной Java даже в будущем.
В чем проблема, с которой вы столкнулись? –
Возможно, что-то вроде [этого] (http://stackoverflow.com/questions/25735407/validate-item-fall-within-start-date-and-end-date/25735601#25735601) или [это] (http: /stackoverflow.com/questions/20677541/date-range-in-date-range/20678485#20678485) – MadProgrammer
Можете ли вы использовать Java 8 или время Joda? – assylias