Предполагая, что каждый интервал находится в пределах либо AM, либо PM
Я предполагаю, что каждый интервал полностью находится в пределах AM (с 00:00 до 12) или PM (с 12:00 до 00). Я не понял, что вы имели в виду под «(+/- 30 минут)», поэтому я проигнорировал это.
В целом, я считаю это искусственным испытанием. В реальном мире 2 часа ночи и 2 часа дня - это не одно и то же, просто они имеют одинаковое представление на 12-часовых часах. Точно так же, как флагшток и человек из Польши не одинаковы, хотя у них обоих есть представление «Полюс».
Как предложил Свипер в комментарии, я конвертирую каждый интервал в AM (если это было в PM). ) до сопоставления.
LocalTime begin1 = LocalTime.of(1, 0);
LocalTime end1 = LocalTime.of(3, 0);
LocalTime begin2 = LocalTime.of(13, 45);
LocalTime end2 = LocalTime.of(14, 45);
// Convert interval 1 to AM
if (begin1.get(ChronoField.AMPM_OF_DAY) == 1) { // PM
begin1 = begin1.minusHours(12);
end1 = end1.minusHours(12);
}
// validate
if (end1.isBefore(begin1)) {
throw new IllegalStateException("end1 " + end1 + " must not be before begin1 " + begin1);
}
if (end1.isAfter(LocalTime.NOON)) {
throw new IllegalStateException("Interval 1 must be completely within either AM or PM");
}
// Convert interval 2 to AM
if (begin2.get(ChronoField.AMPM_OF_DAY) == 1) {
begin2 = begin2.minusHours(12);
end2 = end2.minusHours(12);
}
// validate
if (end2.isBefore(begin2)) {
throw new IllegalStateException("end2 " + end2 + " must not be before begin2 " + begin2);
}
if (end2.isAfter(LocalTime.NOON)) {
throw new IllegalStateException("Interval 2 must be completely within either AM or PM");
}
if (end2.isAfter(begin1) && end1.isAfter(begin2)) {
System.out.println("They overlap");
} else {
System.out.println("They do not overlap");
}
Выходные данные из этого кода:
Они перекрываются
Угловой случай: я принимаю время окончания 12 : 00 (полдень) для интервала AM и 00:00 для интервала PM. У LocalTime.minusHours()
есть циклический c недостаток, поэтому вычитание 12 часов с 00:00 дает 12: 00.
Код может быть проще и проще, если вы определите класс TimePeriod
с помощью поля для начала и конца, метод проверки перекрытия и вспомогательный метод для преобразования в AM.
Без ограничений
Редактировать: Предполагая, что каждый интервал может иметь любую длину от 0 (включительно) до 24 часов (не включительно) и может пересекать 00:00, это несколько сложнее, но я не мог позволить заданию отдохнуть.
Некоторые наблюдения:
- Если один интервал составляет 12 часов или более, а другой имеет ненулевую длину, оба обязательно перекрываются.
- Если оба интервала короче 12 часов, то, если они не перекрываются, мы можем go (считать) циклически вперед от
begin1
до end1
и begin2
до end2
в указанном здесь порядке и либо не пересекают 12 часов или пересекают 12 один раз и заканчиваются раньше begin1
. Если этот цикл не работает, интервалы должны как-то перекрываться.
В коде:
public static boolean overlaps(LocalTime begin1, LocalTime end1, LocalTime begin2, LocalTime end2) {
if (begin1.equals(end1)) { // zero length, cannot overlap anything
return false;
}
if (begin2.equals(end2)) {
return false;
}
// If any interval is 12 hours or longer,
// the other one is necessarily included, that is, overlaps
if (is12HoursOrLonger(begin1, end1)) {
return true;
}
if (is12HoursOrLonger(begin2, end2)) {
return true;
}
// Convert all times to AM
begin1 = toAm(begin1);
end1 = toAm(end1);
begin2 = toAm(begin2);
end2 = toAm(end2);
// For the two intervals *not* to overlap we must be able to go forward
// from begin1 through end1 and begin2 to end2 in this order either
// not crossing 12 or crossing 12 once and ending before or on begin1
boolean crossed12OClock = false;
if (end1.isBefore(begin1)) { // to go forward to end1 we are crossing 12 o’clock
crossed12OClock = true;
}
if (begin2.isBefore(end1)) {
if (crossed12OClock) {
// crossing 12 for the second time;
// intervals cannot be in non-overlapping order
return true;
}
crossed12OClock = true;
}
if (end2.isBefore(begin2)) {
if (crossed12OClock) {
return true;
}
crossed12OClock = true;
}
if (crossed12OClock) {
return end2.isAfter(begin1);
} else {
return false;
}
}
Этот метод использует следующие два вспомогательных метода:
private static boolean is12HoursOrLonger(LocalTime begin, LocalTime end) {
Duration length = Duration.between(begin, end);
if (length.isNegative()) {
length = length.plusDays(1);
}
return ! length.minusHours(12).isNegative();
}
private static LocalTime toAm(LocalTime time) {
return time.with(ChronoField.AMPM_OF_DAY, 0);
}
Давайте попробуем это, используя время, указанное ранее:
if (overlaps(begin1, end1, begin2, end2)) {
System.out.println("They overlap");
} else {
System.out.println("They do not overlap");
}
Они перекрываются
Поскольку код и аргументы сложны, убедитесь, что методы тщательно с юнит-тестами.