package com.wilutions.fx.util; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.FormatStyle; import java.util.Locale; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.control.DatePicker; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.util.StringConverter; // http://stackoverflow.com/questions/28493097/is-there-any-date-and-time-picker-available-for-javafx public class DateTimePicker extends DatePicker { public static final String DefaultFormat = DateTimeFormatterBuilder.getLocalizedDateTimePattern( FormatStyle.MEDIUM, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.GERMANY); // or whatever Locale private DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DefaultFormat); private ObjectProperty<LocalDateTime> dateTimeValue = new SimpleObjectProperty<>(LocalDateTime.now()); private ObjectProperty<String> format = new SimpleObjectProperty<String>() { public void set(String newValue) { super.set(newValue); formatter = DateTimeFormatter.ofPattern(newValue); } }; public DateTimePicker() { getStyleClass().add("datetime-picker"); setConverter(new InternalConverter()); // Syncronize changes to the underlying date value back to the // dateTimeValue valueProperty().addListener((observable, oldValue, newValue) -> { if (newValue == null) { dateTimeValue.set(null); } else { if (dateTimeValue.get() == null) { dateTimeValue.set(LocalDateTime.of(newValue, LocalTime.now())); } else { LocalTime time = dateTimeValue.get().toLocalTime(); dateTimeValue.set(LocalDateTime.of(newValue, time)); } } }); // Syncronize changes to dateTimeValue back to the underlying date value dateTimeValue.addListener((observable, oldValue, newValue) -> { setValue(newValue == null ? null : newValue.toLocalDate()); }); // Persist changes onblur getEditor().focusedProperty().addListener((observable, oldValue, newValue) -> { if (!newValue) simulateEnterPressed(); }); } private void simulateEnterPressed() { getEditor().fireEvent(new KeyEvent(getEditor(), getEditor(), KeyEvent.KEY_PRESSED, null, null, KeyCode.ENTER, false, false, false, false)); } public LocalDateTime getDateTimeValue() { return dateTimeValue.get(); } public void setDateTimeValue(LocalDateTime dateTimeValue) { if (dateTimeValue.isAfter(LocalDateTime.of(1971, 6, 30, 12, 00))) this.dateTimeValue.set(dateTimeValue); else this.dateTimeValue.set(null); } public ObjectProperty<LocalDateTime> dateTimeValueProperty() { return dateTimeValue; } public String getFormat() { return format.get(); } public ObjectProperty<String> formatProperty() { return format; } public void setFormat(String format) { this.format.set(format); } class InternalConverter extends StringConverter<LocalDate> { public String toString(LocalDate object) { LocalDateTime value = getDateTimeValue(); return (value != null) ? value.format(formatter) : ""; } public LocalDate fromString(String value) { if (value == null || value.isEmpty()) { dateTimeValue.set(null); return null; } dateTimeValue.set(LocalDateTime.parse(value, formatter)); return dateTimeValue.get().toLocalDate(); } } }