Подтвердить что ты не робот

Взаимное ограничение времени начала и окончания даты с использованием p: calendar (без проверки)

У нас есть требование представить два компонента p: calendar пользователю, представляя каждую дату начала и окончания. Оба времени имеют даты, часы и минуты. PrimeFaces имеет отличные атрибуты mindate, maxdate, minHour, maxHour, minMinute и minMinute.

Теперь требуется следующее:

Невозможно установить начальное значение datetime на значение, большее или равное концу datetime. Невозможно установить конец datetime на что-либо меньшее или равное концу datetime.

Следующее уравнение должно иметь значение:

begin datetime < end datetime

Теперь мы попробовали следующий JSF:

<p:calendar id="begin-date"
            value="#{debugManager.selectedBeginDate}"
            mindate="#{debugManager.minBeginDate}"
            maxdate="#{debugManager.maxBeginDate}"
            maxHour="#{debugManager.maxBeginHour}"
            maxMinute="#{debugManager.maxBeginMinute}"
            pattern="yyyy-MM-dd HH:mm"
            showButtonPanel="true"
            readonlyInput="true"
            navigator="true"
            showOn="button"
            required="true">
    <p:ajax event="dateSelect" update="end-date" />
</p:calendar>

<p:calendar id="end-date"
            value="#{debugManager.selectedEndDate}"
            mindate="#{debugManager.minEndDate}"
            minHour="#{debugManager.minEndHour}"
            minMinute="#{debugManager.minEndMinute}"
            pattern="yyyy-MM-dd HH:mm"
            showButtonPanel="true"
            readonlyInput="true"
            navigator="true"
            showOn="button">
    <p:ajax event="dateSelect" update="begin-date" />
</p:calendar>

Здесь примерный метод min/max (отзыв даты окончания):

public Date getMinEndDate()
{
    return this.getSelectedBeginDate();
}

Как вы можете видеть, минимальная дата окончания - это текущая дата начала AJAX. Установка даты окончания корректно запрещает установку даты начала за датой окончания.

Проблемы начинаются с вовлечения времени в уравнение...

Поскольку интерфейс p: calendar имеет отдельные методы, bean должен предоставить логику:

public int getMinEndHour()
{
    Date selectedBeginDate = this.getSelectedBeginDate();
    Date selectedEndDate = this.getSelectedEndDate();

    if ( selectedBeginDate != null && DateUtil.isSameDay( selectedBeginDate, selectedEndDate ) )
    {
        return DateUtil.getHourOf( selectedBeginDate );
    }

    return ComplianceConstants.DEFAULT_COMPLIANCE_CASE_MIN_END_HOUR;
}

В основном это говорит только о том, была ли установлена ​​дата начала, и даты начала и окончания в настоящее время одинаковы, ограничить выбранный конечный час (minHour конечной даты) до часа начала.

Операции:

Set the begin datetime to 2013-04-20 12:34 (legit)
Set the end   datetime to 2013-04-22 00:00 (legit)

Теперь время для конечной даты будет установлено в 00:00, а выбор даты календаря 2013-04-20 должен быть разрешен до тех пор, пока время окончания будет каким-то образом скорректировано как минимум на 12:35.

Компонент p: calendar, однако, не может знать этого и сейчас

sets the end datetime to 2013-04-20 00:00 (legit, but false)

...

Теперь проблема заключается в том, что когда пользователь нажимает определенную новую дату окончания в календаре, атрибуты mindate/maxdate не могут ограничить пользователя ударом того же самого, что и дата начала. Если дата окончания время теперь до того, как то же самое время начала, мы ничего не можем с этим поделать (что неправильно).

Теперь проблема заключается в том, что пользователь может закрыть календарь и просто нажать кнопку отправки, чтобы вставить ложные данные в БД. Конечно, валидатор может/должен быть запущен, но нам нужно как-то добиться этого без валидатора.

То, что мы пытались сделать дальше, - исправить методы setSelectedBeginDate( Date selectedBeginDate ) и setSelectedEndDate( Date selectedEndDate ), чтобы отрегулировать временные фрагменты java.util.Date, если даты были в тот же день. Что-то вроде этого:

public void adjustSelectedEndDate()
{
    if ( this.selectedEndDate != null )
    {
        this.log.infov( "adjustSelectedEndDate: b-hour = {0}, e-hour = {1}", DateUtil.getHourOf( this.selectedBeginDate ), DateUtil.getHourOf( this.selectedEndDate ) );

        if ( DateUtil.isSameDay( this.selectedBeginDate, this.selectedEndDate ) &&
            ( DateUtil.getHourOf( this.selectedEndDate ) < DateUtil.getHourOf( this.selectedBeginDate ) ) ||
              DateUtil.getHourOf( this.selectedEndDate ) == DateUtil.getHourOf( this.selectedBeginDate ) && DateUtil.getMinuteOf( this.selectedEndDate ) <= DateUtil.getMinuteOf( this.selectedBeginDate ) )
        {
            this.log.info( "Adjusting selected end date!" );

            this.selectedEndDate = DateUtil.addOneMinuteTo( DateUtil.copyTime( this.selectedBeginDate, this.selectedEndDate ) );
        }
    }
}

Это потребовало, чтобы мы добавили @this к атрибуту update каждого p:calendar, чтобы в процессе обновления вызывались соответствующие геттеры (getSelectedBeginDate() и getSelectedEndDate + ограничители min/max).

Размещение @this в обновлении, однако, смущает компоненты p: calendar, делая ползунки времени только скользящими один раз. Последующие события слайдера просто игнорируются, они ведут себя сломанно.

Q-х

  • Как вы обычно подходите к решению этого вопроса?
  • Использует p:remoteCommand способ достижения желаемого?

Необязательный Q:

  • Почему не был реализован календарь PrimeFaces p: calendar для предоставления одного minDateTime и maxDateTime, что потенциально может решить проблемы?

Готов поспорить, этот сценарий, который я описал, уже был решен ранее. Я был бы очень признателен, если бы вы могли описать подход, который вам удалось решить (или даже частично разрешить).

4b9b3361

Ответ 1

Введение:

Я не работаю с JSF, но есть несколько вещей, которые могут вернуть вас туда, где вы хотите:

a), когда работает только с датой dateTime в стандартном календаре, рассмотрите возможность использования:

someCalendar.set(Calendar.MILLISECOND, 0)

b) рассмотрите возможность использования joda-time, поскольку это часто рекомендуется (здесь, здесь и много других мест) по стандартной библиотеке для правильности, производительности и простота использования во многих ситуациях.

c) Убедитесь, что ваша область bean выдержала каждый вызов ajax (не перенаправляя, отправляя только стандартные пост-обратные ссылки и т.д.), и каждый обработчик событий получает контекст лиц (например. FacesContext facesContext = FacesContext.getCurrentInstance();)

d) mindate и т.д., вероятно, не работают так, как вы ожидаете, и я не ожидаю, что автоматическое поведение может быть настолько легко вложено.

Если эти параметры недоступны, и вы должны сделать все сами с тем, что у вас есть:

Философский/UX: Первое, что я хотел бы сделать, это удалить ожидаемое расположение или перспективу из пары дат. Не рассматривайте пару как вектор, который предоставляет или ожидает направление на временной шкале.

  • Другими словами, дата start или from всегда меньше или меньше даты end или to? Нет, как видно из запроса исторических данных или для внесения исправлений в события, которые либо еще не произошли, либо уже произошли?

    Эта коннотация может легко путать пользователя с вопросом, вернутся ли они к "назад" или "вперед" (и может легко смутить себя). Вместо этого я рассматривал бы пару дат с временным периодом между ними как просто и просто, что a pair of dates или range или period, объявляющие интервал, и выводят их относительное положение на временной шкале в зависимости от любого следовательно, выбранные значения. Таким образом, вы можете соблюдать соответствующие и неотъемлемые требования, чтобы даты никогда не были равны, а левые всегда слева, справа - вправо.

Мы не можем сделать вывод о том, что означает "начало" или "от", но мы можем заключить какое-то значение и относительную взаимосвязь: справа, слева и между ними на хронологической шкале времени. Примечание. Всегда разрешайте даты в формате UTC перед выполнением любых вычислений или сравнения.

long oneDateValue = oneDate.toUtc().toMilliseconds();
long anotherDateValue = anotherDate.toUtc().toMilliseconds();

long right = max (oneDateValue, anotherDateValue);
long left = min (oneDateValue, anotherDateValue);

Оценка точности: Во-вторых, я бы посмотрел, когда работа с диапазоном дат на любом языке похожа на то, как вы можете иметь дело с числами с плавающей запятой. Для сравнения не сравнивайте для равенства, а сравнивайте дельта с "допустимым уровнем ошибки". Другими словами, приложение действительно связано только с определенной степенью точности, поэтому убедитесь, что только эта точность захвачена и рассмотрена:

const int dateTimeResolutionInMs = 86400000; // milliseconds per day

public bool areEssentiallySame(long left, long right) {

   // the difference between right and left is less than our precision 
   // requires, thus dates are effectively the same
   return (right - left < dateTimeResolutionInMs);
}

Прецизионная точность: В-третьих, как мы решаем разницу в значениях, даже если в пределах диапазона разрешения? (Out application получил больше точности, чем может обрабатывать или ожидать или нуждается).

long diff = value % dateTimeResolutionInMs;

  • Усекать: return value - diff;

  • Ближайшее (w/смещение): return value + (diff < dateTimeResolutionInMs/ 2) ? -1 * diff : dateTimeResolutionInMs - diff;

  • Другие: существует множество других стратегий для сокращения или расширения значения до предпочтительного разрешения или точности

Приложение: Что касается вызова post-backs/Ajax для возврата представления со значениями, которые вы ожидаете для событий, инициированных элементом calendar, вы можете отделить эту проблему до нового вопроса, если примечание в предисловии didn ' t вы получите где угодно, и вы знаете наверняка, что ваш bean правильно зарегистрирован и распознан. У вас могут быть определенные проблемы с браузером/браузером, которые способствуют нежелательному поведение и, как и все остальное, есть проблемы, известные и неизвестные.