Взаимное ограничение времени начала и окончания даты с использованием 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, что потенциально может решить проблемы?
Готов поспорить, этот сценарий, который я описал, уже был решен ранее. Я был бы очень признателен, если бы вы могли описать подход, который вам удалось решить (или даже частично разрешить).
Ответы
Ответ 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 правильно зарегистрирован и распознан. У вас могут быть определенные проблемы с браузером/браузером, которые способствуют нежелательному поведение и, как и все остальное, есть проблемы, известные и неизвестные.