TimePicker is a highly configurable component to integrate time inputs (hours / minutes) in a convenient way. A typical area of application is working time registration, expense and travel accounts. See the Internationalisation page for how to localize the component in multi-language applications.
Time picker has three modes: inline, popup and spinner. The spinner is the most convenient because it increments / decrements hours and minutes, but it is not compatible with onHourShow / onMinuteShow. The customized picker sets the time separator, start / end hours and minutes, the minute interval, buttons and more.
AJAX events timeSelect, beforeShow and close, hours-only and minutes-only pickers, restricted time via onHourShow / onMinuteShow callbacks, and a custom locale (try "Change Locale").
Time picker supports minimum and maximum hours and minutes. They can also be set from JavaScript with the widget methods setMinTime(hour, minute) and setMaxTime(hour, minute).
Two time pickers select a chronological time range: the first is restricted to times before the one selected in the second, and vice versa. The JavaScript callbacks below also provide the restricted time used by the previous card.
<style>
.timepicker-column {
padding: 0 1rem 1rem 0;
vertical-align: top;
}
</style>
<div class="card">
<h5>Basic usage and three modes</h5>
<p>Time picker has three modes: <code>inline</code>, <code>popup</code> and <code>spinner</code>. The spinner is the most convenient because it increments / decrements hours and minutes, but it is not compatible with <code>onHourShow</code> / <code>onMinuteShow</code>. The customized picker sets the time separator, start / end hours and minutes, the minute interval, buttons and more.</p>
<h:form id="formBasicUsage">
<p:messages id="messages"/>
<h:panelGroup id="timePickerGroup" layout="block">
<p>
Inline mode
<pe:timePicker value="#{timePickerController.time1}" mode="inline" widgetVar="inlineTimeWidget"
label="Inline time picker"/>
</p>
<p>
Popup mode
<pe:timePicker value="#{timePickerController.time2}" mode="popup" widgetVar="popupTimeWidget"
label="Popup time picker"/>
</p>
<p>
Spinner mode
<pe:timePicker value="#{timePickerController.time3}" widgetVar="spinnerTimeWidget"
label="Spinner time picker"/>
</p>
<p>
Customization
<pe:timePicker value="#{timePickerController.time4}" timeSeparator="-" startHours="8" endHours="20"
startMinutes="10" endMinutes="40" intervalMinutes="10" showCloseButton="true"
showDeselectButton="true" showNowButton="true" rows="3" showPeriod="true" size="8"
widgetVar="customTimeWidget" label="Custom time picker" required="true" requiredMessage="Customization is required!"/>
</p>
<p>
Show popup by button
<pe:timePicker value="#{timePickerController.time5}" mode="popup" widgetVar="popupBtnTimeWidget"
showOn="button" label="Popup time picker with button"/>
</p>
<p>
Spinner with button
<pe:timePicker value="#{timePickerController.time6}" mode="spinner" widgetVar="spinnerBtnTimeWidget"
showOn="button" label="Spinner time picker with button"/>
</p>
</h:panelGroup>
<p:commandButton type="button" value="Disable time pickers" styleClass="mt-2 mr-2"
onclick="PF('inlineTimeWidget').disable();PF('popupTimeWidget').disable();
PF('spinnerTimeWidget').disable();PF('customTimeWidget').disable();
PF('popupBtnTimeWidget').disable();PF('spinnerBtnTimeWidget').disable();"/>
<p:commandButton type="button" value="Enable time pickers" styleClass="mt-2 mr-2"
onclick="PF('inlineTimeWidget').enable();PF('popupTimeWidget').enable();
PF('spinnerTimeWidget').enable();PF('customTimeWidget').enable();
PF('popupBtnTimeWidget').enable();PF('spinnerBtnTimeWidget').enable();"/>
<p:commandButton id="submitButton" value="Submit" actionListener="#{timePickerController.showTime}"
process="@this timePickerGroup" update="messages timeDialog timePickerGroup"
styleClass="mt-2 mr-2" icon="pi pi-save"/>
<p:dialog id="timeDialog" header="Selected Values" visible="#{timePickerController.showTimeDialog}">
<h:panelGrid columns="1" style="margin: 10px;">
<h:outputText value="Inline: #{timePickerController.formattedTime1}"/>
<h:outputText value="Popup: #{timePickerController.formattedTime2}"/>
<h:outputText value="Spinner: #{timePickerController.formattedTime3}"/>
<h:outputText value="Custom: #{timePickerController.formattedTime4}"/>
<h:outputText value="Button: #{timePickerController.formattedTime5}"/>
<h:outputText value="Spinner and Button: #{timePickerController.formattedTime6}"/>
</h:panelGrid>
</p:dialog>
</h:form>
</div>
<div class="card">
<h5>Advanced usage, events and callbacks</h5>
<p>AJAX events <i>timeSelect</i>, <i>beforeShow</i> and <i>close</i>, hours-only and minutes-only pickers, restricted time via <code>onHourShow</code> / <code>onMinuteShow</code> callbacks, and a custom locale (try "Change Locale").</p>
<h:form id="formAdvancedUsage">
<p:growl id="growl" showDetail="true" showSummary="true"/>
<h:panelGrid id="timePickerGrid" columns="5" columnClasses="timepicker-column">
<h:outputText value="TimeSelect event"/>
<h:outputText value="BeforeShow / Close events"/>
<h:outputText value="Only hours"/>
<h:outputText value="Only minutes"/>
<h:outputText value="Restricted time"/>
<pe:timePicker id="inlineTime" value="#{timePickerController.time1}" mode="inline" locale="#{timePickerController.locale}">
<p:ajax event="timeSelect" listener="#{timePickerController.timeSelectListener}" update="growl"/>
</pe:timePicker>
<pe:timePicker id="spinnerTime" value="#{timePickerController.time2}" showPeriod="true" style="width: 100px;" locale="#{timePickerController.locale}">
<p:ajax event="beforeShow" listener="#{timePickerController.beforeShowListener}" update="growl"/>
<p:ajax event="close" listener="#{timePickerController.closeListener}" update="growl"/>
</pe:timePicker>
<pe:timePicker value="#{timePickerController.time4}" showMinutes="false" locale="#{timePickerController.locale}"/>
<pe:timePicker value="#{timePickerController.time4}" showHours="false" locale="#{timePickerController.locale}"/>
<pe:timePicker value="#{timePickerController.time4}" mode="popup" locale="#{timePickerController.locale}"
onHourShow="onHourShowCallback" onMinuteShow="onMinuteShowCallback"/>
<p:commandButton id="localeButton" value="Change Locale" actionListener="#{timePickerController.changeLocale}"
process="@this" update="@parent" style="margin-top:10px;" icon="pi pi-save"/>
</h:panelGrid>
</h:form>
<script>
PrimeFacesExt.locales.TimePicker['pt_BR'] = {
hourText: 'Horas',
minuteText: 'Minutos',
amPmText: ['AM', 'PM'],
closeButtonText: 'Fechar',
nowButtonText: 'Agora',
deselectButtonText: 'Limpar seleção'
};
</script>
</div>
<div class="card">
<h5>Setting min. / max. time</h5>
<p>Time picker supports minimum and maximum hours and minutes. They can also be set from JavaScript with the widget methods <code>setMinTime(hour, minute)</code> and <code>setMaxTime(hour, minute)</code>.</p>
<h:form id="formMinMaxTime">
<pe:timePicker mode="inline" minHour="9" minMinute="15"
maxHour="16" maxMinute="30"/>
</h:form>
</div>
<div class="card">
<h5>Time range</h5>
<p>Two time pickers select a chronological time range: the first is restricted to times before the one selected in the second, and vice versa. The JavaScript callbacks below also provide the restricted time used by the previous card.</p>
<h:form id="formTimeRange">
<h:panelGrid columns="5" cellpadding="4">
<h:outputText value="Start time"/>
<pe:timePicker value="#{timePickerController.time1}" mode="popup" onHourShow="tpStartOnHourShowCallback"
onMinuteShow="tpStartOnMinuteShowCallback" widgetVar="startTimeWidget"/>
<h:panelGroup layout="block" style="width:20px;"/>
<h:outputText value="End time"/>
<pe:timePicker value="#{timePickerController.time2}" mode="popup" onHourShow="tpEndOnHourShowCallback"
onMinuteShow="tpEndOnMinuteShowCallback" widgetVar="endTimeWidget"/>
</h:panelGrid>
</h:form>
<script>
/* <![CDATA[ */
function onHourShowCallback(hour) {
if ((hour > 20) || (hour < 6)) {
return false; // not valid
}
return true; // valid
}
function onMinuteShowCallback(hour, minute) {
if ((hour == 20) && (minute >= 30)) {
return false; // not valid
}
if ((hour == 6) && (minute < 30)) {
return false; // not valid
}
return true; // valid
}
function tpStartOnHourShowCallback(hour) {
if (!PrimeFaces.widgets['endTimeWidget']) {
return false;
}
var tpEndHour = parseInt(PF('endTimeWidget').getHours());
// Check if proposed hour is prior or equal to selected end time hour
if (parseInt(hour) <= tpEndHour) {
return true;
}
// if hour did not match, it can not be selected
return false;
}
function tpStartOnMinuteShowCallback(hour, minute) {
if (!PrimeFaces.widgets['endTimeWidget']) {
return false;
}
var tpEndHour = parseInt(PF('endTimeWidget').getHours());
var tpEndMinute = parseInt(PF('endTimeWidget').getMinutes());
// Check if proposed hour is prior to selected end time hour
if (parseInt(hour) < tpEndHour) {
return true;
}
// Check if proposed hour is equal to selected end time hour and minutes is prior
if ((parseInt(hour) == tpEndHour) && (parseInt(minute) < tpEndMinute)) {
return true;
}
// if minute did not match, it can not be selected
return false;
}
function tpEndOnHourShowCallback(hour) {
if (!PrimeFaces.widgets['startTimeWidget']) {
return false;
}
var tpStartHour = parseInt(PF('startTimeWidget').getHours());
// Check if proposed hour is after or equal to selected start time hour
if (parseInt(hour) >= tpStartHour) {
return true;
}
// if hour did not match, it can not be selected
return false;
}
function tpEndOnMinuteShowCallback(hour, minute) {
if (!PrimeFaces.widgets['startTimeWidget']) {
return false;
}
var tpStartHour = parseInt(PF('startTimeWidget').getHours());
var tpStartMinute = parseInt(PF('startTimeWidget').getMinutes());
// Check if proposed hour is after selected start time hour
if (parseInt(hour) > tpStartHour) {
return true;
}
// Check if proposed hour is equal to selected start time hour and minutes is after
if ((parseInt(hour) == tpStartHour) && (parseInt(minute) > tpStartMinute)) {
return true;
}
// if minute did not match, it can not be selected
return false;
}
/* ]]> */
</script>
</div>
package org.primefaces.extensions.showcase.controller;
import java.io.Serial;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.Calendar;
import java.util.Date;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.faces.event.ActionEvent;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import org.apache.commons.lang3.Strings;
import org.primefaces.extensions.event.BeforeShowEvent;
import org.primefaces.extensions.event.CloseEvent;
import org.primefaces.extensions.event.TimeSelectEvent;
/**
* TimePickerController using java.util.Date and java.time.LocalTime.
*
* @author ova / last modified by Melloware
*/
@Named
@ViewScoped
public class TimePickerController implements Serializable {
@Serial
private static final long serialVersionUID = 20120224L;
private Date time1;
private Date time2;
private LocalTime time3;
private LocalTime time4;
private LocalTime time5;
private Date time6;
private boolean showTime = false;
private String locale = "en_US";
public TimePickerController() {
final Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.AM_PM, Calendar.AM);
calendar.set(Calendar.HOUR, 8);
calendar.set(Calendar.MINUTE, 15);
time1 = calendar.getTime();
calendar.set(Calendar.HOUR, 11);
calendar.set(Calendar.MINUTE, 40);
time2 = calendar.getTime();
time3 = LocalTime.now();
time5 = LocalTime.now();
time6 = new Date();
}
public Date getTime1() {
return time1;
}
public void setTime1(final Date time1) {
this.time1 = time1;
}
public Date getTime2() {
return time2;
}
public void setTime2(final Date time2) {
this.time2 = time2;
}
public LocalTime getTime3() {
return time3;
}
public void setTime3(final LocalTime time3) {
this.time3 = time3;
}
public LocalTime getTime4() {
return time4;
}
public void setTime4(final LocalTime time4) {
this.time4 = time4;
}
public LocalTime getTime5() {
return time5;
}
public void setTime5(final LocalTime time5) {
this.time5 = time5;
}
public Date getTime6() {
return time6;
}
public void setTime6(final Date time6) {
this.time6 = time6;
}
public String getLocale() {
return locale;
}
public void setLocale(final String locale) {
this.locale = locale;
}
public String getFormattedTime1() {
return getFormattedTime(time1, "HH:mm");
}
public String getFormattedTime2() {
return getFormattedTime(time2, "HH:mm");
}
public String getFormattedTime3() {
return getFormattedTime(time3, "HH:mm");
}
public String getFormattedTime4() {
return getFormattedTime(time4, "hh-mm a");
}
public String getFormattedTime5() {
return getFormattedTime(time5, "HH:mm");
}
public String getFormattedTime6() {
return getFormattedTime(time6, "HH:mm");
}
public void showTime(final ActionEvent ae) {
showTime = true;
}
public void changeLocale(final ActionEvent ae) {
if (Strings.CI.equals(locale, "pt_BR")) {
locale = "en_US";
}
else {
locale = "pt_BR";
}
}
public boolean isShowTimeDialog() {
if (showTime) {
showTime = false;
return true;
}
return false;
}
public void timeSelectListener(final TimeSelectEvent<Date> timeSelectEvent) {
final FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Time select fired",
"Selected time: " + getFormattedTime(timeSelectEvent.getTime(), "HH:mm"));
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public void beforeShowListener(final BeforeShowEvent beforeShowEvent) {
final FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Before show fired",
"Component id: " + beforeShowEvent.getComponent().getId());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public void closeListener(final CloseEvent closeEvent) {
final FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Close fired",
"Component id: " + closeEvent.getComponent().getId());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
private String getFormattedTime(final Date time, final String format) {
if (time == null) {
return null;
}
final SimpleDateFormat formatter = new SimpleDateFormat(format);
return formatter.format(time);
}
private String getFormattedTime(final Temporal time, final String format) {
if (time == null) {
return null;
}
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
return formatter.format(time);
}
}