2013-12-19 6 views
1

На самом деле эта задача казалась очень легко для меня, но я получил немного застрял и был бы благодарен за некоторые намеки: DДиапазон дат в диапазоне дат

У меня есть несколько событий с начала и окончания времени - и Я хотел бы создать таблицу с календарными неделями.

Поэтому я написал метод, чтобы проверить, если событие в течение этой недели, чтобы окрасить это так:

enter image description here

private boolean inWeek(Date date, Entry pe) { 
    return ((pe.getStartsAt().after(Util.firstDayOfWeek(date)) || pe.getStartsAt().equals(Util.firstDayOfWeek(date))) 
    && (pe.getEndsAt().before(Util.lastDayOfWeek(date)) || pe.getEndsAt().equals(Util.lastDayOfWeek(date)))); 
} 

Этот случай был в порядке, если события только продолжительностью одна неделя. но что, если событие начинается до этой недели или заканчивается после этой недели или длится несколько недель?

он стал очень сложным и мое текущее решение было это:

private boolean inWeek(Date date, Entry pe) { 

    return ( pe.getStartsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().before(Util.lastDayOfWeek(date)) ) 
    ||  ( pe.getStartsAt().before(Util.lastDayOfWeek(date)) && pe.getStartsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().after(Util.lastDayOfWeek(date)) ) 
    ||  ( pe.getStartsAt().after(Util.firstDayOfWeek(date)) && pe.getEndsAt().before(Util.lastDayOfWeek(date)) ) 
    ||  ( pe.getStartsAt().before(Util.firstDayOfWeek(date)) && pe.getEndsAt().after(Util.lastDayOfWeek(date))); 

} 

но РВП еще не показывает правильную окраску в некоторых клетках. У кого-нибудь есть какие-то намеки на меня?

(... не предлагая раз Joda ^^)

+0

что параметр дата должно означать, что вы передаете в? –

+0

это простые объекты дат java. Каждая «запись» имеет объект даты как дату начала и дату окончания, а класс «Util» возвращает объекты даты для даты ввода для доставки понедельника и воскресенья (в моем случае для каждой ячейки). –

+0

Почему вы не хотите использовать йоду? – bobah

ответ

0

Я попробовал другое решение - которое, казалось, прекрасно работать, но я не совсем уверен,

private boolean inWeek(Date date, Entry pe) { 
     return ((pe.getEndsAt().after(Util.firstDayOfWeek(date)) || pe.getEndsAt().equals(Util.firstDayOfWeek(date))) 
      && (pe.getStartsAt().before(Util.lastDayOfWeek(date)) || pe.getStartsAt().equals(Util.lastDayOfWeek(date)))); 
} 
0

Я хотел бы сделать код более читаемым для a начало

private boolean inWeek(Date date, Entry pe) { 

    Date eventStart = pe.getStartsAt(); 
    Date eventEnd = pe.getEndsAt(); 
    Date firstDay = Util.firstDayOfWeek(date); 
    Date lastDay = Util.lastDayOfWeek(date); 

    boolean isInweek = (eventStart.after(firstDay) && 
          eventEnd.after(firstDay) && 
          eventEnd.before(lastDay)) 
      || 
         (eventStart.before(lastDay) && 
          eventStart.after(firstDay) && 
          eventEnd.after(lastDay)) 
      || 
         (eventStart.after(firstDay) && 
          eventEnd.before(lastDay)) 
      || 
         (eventStart.before(firstDay) && 
          eventEnd.after(lastDay)); 

    return isInweek; 

} 

Это, вероятно, сделает проблему более заметной.

У вас есть eventEnd.after (lastDay) во втором блоке. Я не думаю, что это так.

И первый блок избыточен, потому что третий блок будет точно таким же.

Неужели этого достаточно?

private boolean inWeek(Date date, Entry pe) { 

    Date eventStart = pe.getStartsAt(); 
    Date eventEnd = pe.getEndsAt(); 
    Date firstDay = Util.firstDayOfWeek(date); 
    Date lastDay = Util.lastDayOfWeek(date); 

    boolean isInweek = 
         (eventStart.after(firstDay) && //event is INSIDE of the week. 
          eventEnd.before(lastDay)) 
      || 
         (eventStart.before(firstDay) && //event is OUTSIDE of the week 
          eventEnd.after(lastDay)); 

    return isInweek; 

} 
+0

В вашем коде событие должно начинаться и заканчиваться в течение определенной недели или начинаться до определенной недели и конца после нее. Что делать, если он начинается между firstDay и lastDay, но заканчивается неделю после определенной недели или начинается за неделю до этого и заканчивается между firstDay и lastDay. – esrange

1

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

С этой целью, если вы будете давать ему идти, я беру бы взглянуть на JodaTime

В принципе, то, что этот пример делает это создает ряд Interval с. Один - это «период», или неделя года (начиная с понедельника и заканчивая в воскресенье).

Один Interval является перекрывание интервал, который охватывает одну неделю до и неделю после «периода», а другой один день Interval в «период»

import org.joda.time.Interval; 
import org.joda.time.MutableDateTime; 
import org.joda.time.Period; 
import org.joda.time.format.DateTimeFormat; 
import org.joda.time.format.DateTimeFormatter; 
import org.joda.time.format.DateTimeFormatterBuilder; 
import org.joda.time.format.DateTimeParser; 

public class TestTimeInterval { 

    public static void main(String[] args) { 

     DateTimeFormatter formatter = new DateTimeFormatterBuilder(). 
         appendDayOfMonth(2).appendLiteral(" "). 
         appendDayOfWeekText().appendLiteral(" "). 
         appendMonthOfYearText().appendLiteral(" "). 
         appendYear(2, 2). 
         toFormatter(); 

     // Last week 
     MutableDateTime targetStart = MutableDateTime.now(); 
     targetStart.setDayOfWeek(1); 
     targetStart.addDays(-6); 

     // Next week 
     MutableDateTime targetEnd = MutableDateTime.now(); 
     targetEnd.setDayOfWeek(7); 
     targetEnd.addDays(7); 

     System.out.println("Target range = " + formatter.print(targetStart) + " to " + formatter.print(targetEnd)); 
     Interval targetInterval = new Interval(targetStart, targetEnd); 

     // This week 
     MutableDateTime start = MutableDateTime.now(); 
     start.setDayOfWeek(1); 

     MutableDateTime end = MutableDateTime.now(); 
     end.setDayOfWeek(7); 

     Interval interval = new Interval(start, end); 

     System.out.println("Interval range = " + formatter.print(start) + " to " + formatter.print(end)); 
     System.out.println("Contains interval = " + targetInterval.contains(interval)); 

     // Last week 
     targetStart = DateTime.now(); 

     // Next week 
     targetEnd = DateTime.now(); 

     System.out.println("Target range = " + formatter.print(targetStart) + " to " + formatter.print(targetEnd)); 
     targetInterval = new Interval(targetStart, targetEnd); 
     System.out.println("Contains interval = " + interval.contains(targetInterval)); 
    } 

} 

который выводит ...

Target range = 10 Tuesday December 2013 to 29 Sunday December 2013 
Period range = 16 Monday December 2013 to 22 Sunday December 2013 
Contains period = true 
Target range = 19 Thursday December 2013 to 19 Thursday December 2013 
Contains period = true 

Что вам нужно, только проверить интервал периода двумя способами.

  1. Чтобы проверить, "период" находится в комплект поставки Interval и
  2. Если подаваемое Interval находится в "период" ...

Например ...

if (period.contains(interval) || interval.contains(period)) { 
    // Match... 
} 

Теперь, есть много других вещей, чтобы рассмотреть, например, если время не важно для Interval s, вы хотите, чтобы нулевое время (начало периода должен быть полночь/утро и конец должна полночь вечер), так что вы максимумы этого района поймать

Обновлены лучшего использование библиотек JodaTime

@BasilBourque смог выделить некоторые проблемы с оригинальными, например, что Я обновил и протестировал соответственно. Благодаря @BasilBourque

Хотя Двойники к оригиналу, он делает лучше использовать JodaTime библиотеки

public static void newWay() { 

    DateTimeFormatter formatter = new DateTimeFormatterBuilder(). 
      appendDayOfMonth(2).appendLiteral(" "). 
      appendDayOfWeekText().appendLiteral(" "). 
      appendMonthOfYearText().appendLiteral(" "). 
      appendYear(2, 2). 
      toFormatter(); 

    // Last week 
    DateTime targetStart = DateTime.now(DateTimeZone.getDefault()). 
      withDayOfWeek(DateTimeConstants.MONDAY). 
      minusDays(6); 
    //MutableDateTime targetStart = MutableDateTime.now(); 
    //targetStart.setDayOfWeek(1); 
    //targetStart.addDays(-6); 

    // Next week 
    DateTime targetEnd = DateTime.now(DateTimeZone.getDefault()). 
      withDayOfWeek(DateTimeConstants.SUNDAY). 
      plusDays(7); 
    //MutableDateTime targetEnd = MutableDateTime.now(); 
    //targetEnd.setDayOfWeek(7); 
    //targetEnd.addDays(7); 

    System.out.println("Target range = " + formatter.print(targetStart) + " to " + formatter.print(targetEnd)); 
    Interval targetInterval = new Interval(targetStart, targetEnd); 

    // This week 
    DateTime start = DateTime.now(DateTimeZone.getDefault()). 
      withDayOfWeek(DateTimeConstants.MONDAY); 
    //MutableDateTime start = MutableDateTime.now(); 
    //start.setDayOfWeek(1); 

    DateTime end = DateTime.now(DateTimeZone.getDefault()). 
      withDayOfWeek(DateTimeConstants.SUNDAY); 
    //MutableDateTime end = MutableDateTime.now(); 
    //end.setDayOfWeek(7); 

    Interval interval = new Interval(start, end); 

    System.out.println("Period range = " + formatter.print(start) + " to " + formatter.print(end)); 

    System.out.println("Contains period = " + targetInterval.contains(interval)); 

    // Last week 
    targetStart = DateTime.now(); 

    // Next week 
    targetEnd = DateTime.now(); 

    System.out.println("Target range = " + formatter.print(targetStart) + " to " + formatter.print(targetEnd)); 
    targetInterval = new Interval(targetStart, targetEnd); 
    System.out.println("Contains period = " + interval.contains(targetInterval)); 

} 
+1

Путь к нулю времени - вызвать ['withTimeAtStartOfDay'] (http://www.joda.org/joda-time/apidocs/org/joda/time/DateTime.html#withTimeAtStartOfDay()). ['Contains'] (http://www.joda.org/joda-time/apidocs/org/joda/time/ReadableInterval.html#contains (org.joda.time.ReadableInstant)) является умным об этом« catch область ", как вы ее называете, потому что (см. doc)' интервалы продолжительности включают момент начала и исключение конца. –

+1

Не нужно использовать изменяемые версии классов Joda-Time. Вы просто бесполезно раскрываете проблемы безопасности потоков. Дизайнеры предполагали, что мы обычно используем непреложные классы. Соответствующие классы возвращают свежие экземпляры DateTime (и т. Д.), Поэтому вы все равно можете писать [«свободный» код] (http://en.wikipedia.org/wiki/Fluent_interface) с цепочкой вызовов. –

+0

@BasilBourque Первоначальное использование 'MutableDateTime' было более удобным, поскольку у меня не было других ссылок. Если бы у меня была «дата» или другой конкретный момент времени для работы, я бы предпочел использовать их, но, исходя из фона «Календарь», это имело наибольший смысл в то время. Мне нравится ссылка на 'withTimeAtStartOfDay', это хорошо знать, спасибо. Большая часть ответа вращается вокруг определения «Содержит период», остальное - наполнитель, чтобы сделать данные для этих примеров ... – MadProgrammer

1

Joda времени

Joda-Time 2,3 библиотека делает эту работу намного проще. Он включает класс Interval с методом overlap.

См. the answer by MadProgrammer для получения аналогичного кода и обсуждения.

Ключевых моментов

Interval класса умный, учитывая начало интервала быть включен и заканчивая эксклюзивные. Вы должны делать сравнения, основанные на логике EQUAL TO ИЛИ БОЛЬШЕ, чем начало, но МЕНЬШЕ, чем остановка. Зачем? Потому что момент перед новым днем ​​бесконечно делится. Вы можете подумать: «Хорошо java.util.Date & Решение Joda-Time разрешает миллисекунды, поэтому я буду использовать .999». Но тогда вы будете удивлены, когда переносите код на новые классы Java Java.time. *, Где время разрешается наносекундами.

Timeline showing (>= start of day 1) and (< start of day 8)

Для поддержки этого сравнения, обратите внимание, что цель недели определяется с помощью вызова withTimeAtStartOfDay. Используйте этот метод, а не пытайтесь создать полночь, установив нулевые элементы времени. Этот метод является умным и управляет временем перехода на летнее время и другими аномалиями, где в определенные часовые пояса не может быть 00:00:00 полночь в определенные дни.

Укажите часовой пояс, а не полагайтесь на значения по умолчанию. Весь код в других ответах не учитывает часовой пояс. Это означает, что они используют часовой пояс по умолчанию для JVM. Как следствие, это приложение получает разные результаты при развертывании на другие компьютеры, установленные в другие часовые пояса. Используйте proper time zone names, а не 3-буквенные коды.

Если ваше приложение относится к людям и местным часовым поясам, вы должны подумать о том, чтобы указать целевую неделю на UTC/GMT (без смещения часового пояса). Обратите внимание: это то, что StackOverflow делает для отслеживания активности каждый день. «День» определяется UTC/GMT.

Эти пункты являются доказательством того, почему вы не должны откатывать свою собственную логику даты и времени. Вместо этого используйте грамотную библиотеку. В Java это означает либо Joda-Time, либо новые классы java.time. * В Java 8 (вдохновленные Joda-Time).

ISO Неделя

К слову, ISO 8601 standard defines a "week" точно. Этот стандарт применяется в других странах и отраслях промышленности в разных странах. Следуя этому стандарту, может оказаться полезным. Случай Joda-Time DateTime знает свой номер недели ISO. Позвоните по телефону myDateTime.weekOfWeakYear().get().

Пример кода

DateTimeZone timeZone = DateTimeZone.forID("Europe/Berlin"); 

Interval weekInQuestion = new Interval(new DateTime(2014, 1, 20, 3, 4, 5, timeZone).withTimeAtStartOfDay(), new DateTime(2014, 1, 27, 3, 4, 5, timeZone).withTimeAtStartOfDay()); 

Interval i1 = new Interval(new DateTime(2014, 1, 2, 3, 4, 5, timeZone), new DateTime(2014, 1, 3, 23, 4, 5, timeZone)); 
Interval i2 = new Interval(new DateTime(2014, 1, 24, 3, 4, 5, timeZone), new DateTime(2014, 1, 26, 23, 59, 59, timeZone)); 
Interval i3 = new Interval(new DateTime(2014, 1, 6, 3, 4, 5, timeZone), new DateTime(2014, 1, 30, 3, 4, 5, timeZone)); 

boolean i1HitsWeekInQuestion = i1.overlaps(weekInQuestion); 
boolean i2HitsWeekInQuestion = i2.overlaps(weekInQuestion); 
boolean i3HitsWeekInQuestion = i3.overlaps(weekInQuestion); 

самосвала утешать ...

System.out.println("weekInQuestion: " + weekInQuestion); 
System.out.println("i1: " + i1 + " hits week: " + i1HitsWeekInQuestion); 
System.out.println("i2: " + i2 + " hits week: " + i2HitsWeekInQuestion); 
System.out.println("i3: " + i3 + " hits week: " + i3HitsWeekInQuestion); 

При запуске ...

weekInQuestion: 2014-01-20T00:00:00.000+01:00/2014-01-27T00:00:00.000+01:00 
i1: 2014-01-02T03:04:05.000+01:00/2014-01-03T23:04:05.000+01:00 hits week: false 
i2: 2014-01-24T03:04:05.000+01:00/2014-01-26T23:59:59.000+01:00 hits week: true 
i3: 2014-01-06T03:04:05.000+01:00/2014-01-30T03:04:05.000+01:00 hits week: true 
Смежные вопросы