JavaFX Table Cell Formatting

If you want to preserve the sorting capabilities of your TableColumn, none of the solutions above is valid: if you convert your Date to a String and show it that way in your TableView; the table will sort it as such (so incorrectly).

The solution I found was subclassing the Date class in order to override the toString() method. There is a caveat here though: the TableView uses java.sql.Date instead of java.util.Date; so you need to subclass the former.

import java.text.SimpleDateFormat;

public class CustomDate extends java.sql.Date {

    public CustomDate(long date) {
        super(date);
    }

    @Override
    public String toString() {
        return new SimpleDateFormat("dd/MM/yyyy").format(this);
    }
}

The table will call that method in order to print the date.

Of course, you need to change too your Date class in the TableColumn declaration to the new subclass:

@FXML
TableColumn<MyObject, CustomDate> myDateColumn;

Same thing when you attach your object attribute to the column of your table:

myDateColumn.setCellValueFactory(new PropertyValueFactory< MyObject, CustomDate>("myDateAttr"));

And finally, for the shake of clarity this is how you declare the getter in your object class:

public CustomDate getMyDateAttr() {
    return new CustomDate(myDateAttr.getTime()); //myDateAttr is a java.util.Date           
}

It took me a while to figure out this due to the fact that it uses java.sql.Date behind the scenes; so hopefully this will save other people some time!


Update for Java FX8:

(I'm not sure it is the good place for that answer, but I get the problem in JavaFX8 and some things have changed, like java.time package)

Some differences with the previous answers: I keep the date type on the column, so I need to use both cellValueFactory and cellFactory. I Make a generic reusable method to generate the cellFactory for all date columns. I use java 8 date for java.time package! But the method could be easily reimplemented for java.util.date.

 @FXML
 private TableColumn<MyBeanUi, ZonedDateTime> dateColumn;

@FXML
public void initialize () {
  // The normal binding to column 
  dateColumn.setCellValueFactory(cellData -> cellData.getValue().getCreationDate());

  //.. All the table initialisation and then
  DateTimeFormatter format = DateTimeFormatter .ofLocalizedDate(FormatStyle.SHORT);
  dateColumn.setCellFactory (getDateCell(format));

}

public static <ROW,T extends Temporal> Callback<TableColumn<ROW, T>, TableCell<ROW, T>> getDateCell (DateTimeFormatter format) {
  return column -> {
    return new TableCell<ROW, T> () {
      @Override
      protected void updateItem (T item, boolean empty) {
        super.updateItem (item, empty);
        if (item == null || empty) {
          setText (null);
        }
        else {
          setText (format.format (item));
        }
      }
    };
  };
}

The advantages are that:

  • The column is typed with a "java8 Date" to avoid the sort problem evoqued by @Jordan
  • The method "getDateCell" is generic and can be used as an util function for all Java8 Time types (Local Zoned etc.)