Hot questions for Using Joda-Time in javafx

Question:

Here is the code from my patient class and the JavaFx code to display it. However, each time I add a new object to the queue and refresh, the time displayed is the current time rather than each individual time...`

public String getTime() {
    DateTime d = new DateTime();

    String s = null;
    s = d.toString();

    return s;
}

public void setTime(String time) {
    this.time = time;
}

I'm using jodatime to convert the current datetime to a string and then display this...

@FXML
private TableColumn<Patient, String> timeColumn;

timeColumn.setCellValueFactory(new PropertyValueFactory<Patient, String>("time"));

Answer:

change your getTime() to :

 public String getTime() {

    DateTime d = new DateTime();

    String s = null;
    s = d.toString();

    return s;
}

to :

    public String getTime() {
    return this.time;
}

Because your getTime() keeps on giving the currentTime, and not actually the time you store using setTime().

Question:


Answer:

The author of both libraries writes on the Joda-Time-website:

Note that Joda-Time is considered to be a largely "finished" project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).

So it is clear you should use the workaround to fully qualify the classnames of Joda-Time only as temporary solution. Instead the intention and official recommendation is to migrate on Java-8-platforms.

Although there is usually no 1:1-migration (some effort is necessary!), the fact that Joda-Time will not be any longer in real development (abandoning many new features, just bugfixing) is a strong argument for migration. Another strong argument in favor of migration is the missing interoperability of Joda-Time with Java-8. The author had got the original plan to support low-level-interfaces like TemporalAccessor but dropped it (probably due to lack of resources). What does this concept mean? Concrete example for interoperability (leaving aside the somehow annoying fact to write fully qualified class names):

With TemporalAccessor-Support you could write:

org.joda.time.LocalDate joda = new org.joda.time.LocalDate(year, month, day);
java.time.LocalDate date = java.time.LocalDate.from(joda);

But actually you must write:

org.joda.time.LocalDate joda = new org.joda.time.LocalDate(year, month, day);
java.time.LocalDate date = java.time.LocalDate.of(joda.getYear(), joda.getMonthOfYear(), joda.getDayOfMonth());

So it is obvious that it is no good idea to support both libraries at the same time in your application.

Question:

I have a TableView with a couple of columns created with FXML:

<TableView fx:id="logTable" BorderPane.alignment="CENTER">
    <columns>
        <TableColumn fx:id="timestampColumn" editable="false" text="Timestamp">
            <cellValueFactory>
                <PropertyValueFactory property="timestamp"/>
            </cellValueFactory>
        </TableColumn>
        <TableColumn fx:id="actionColumn" editable="false" text="Action">
            <cellValueFactory>
                <PropertyValueFactory property="action"/>
            </cellValueFactory>
        </TableColumn>
    </columns>
</TableView>

I then have an object defined like this:

private ObservableList<LogEntry> log = FXCollections.observableArrayList();

which is set as the model for the TableView:

logTable.setItems(log);

The LogEntries look like this:

import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import org.joda.time.DateTime;

public class LogEntry {
    private SimpleObjectProperty<DateTime> timestamp = new SimpleObjectProperty<>();
    private SimpleStringProperty action = new SimpleStringProperty();

    public LogEntry(String format, Object... args) {
        this.timestamp.setValue(new DateTime());
        String s = String.format(format, args);
        System.out.println(s);
        this.action.setValue(s);
    }

    public DateTime getTimestamp() {
        return timestamp.getValue();
    }

    public String getAction() {
        return action.getValue();
    }
}

My question is, how do I specify how the Jodatime DateTimes are converted into strings for displaying? I want to convert them using the current locale (but I want sorting on that column to still work).


Answer:

I haven't worked with Joda Time but have done similar with LocalDateTime.

Here is an example of how that might work.

First you would need to expose the properties::

public class LogEntry {
    private SimpleObjectProperty<LocalDateTime> timestamp = new SimpleObjectProperty<>();
    private SimpleStringProperty action = new SimpleStringProperty();
    public final SimpleObjectProperty<LocalDateTime> timestampProperty() {
        return this.timestamp;
    }

    public final java.time.LocalDateTime getTimestamp() {
        return this.timestampProperty().get();
    }

    public final void setTimestamp(final java.time.LocalDateTime timestamp) {
        this.timestampProperty().set(timestamp);
    }

    public final SimpleStringProperty actionProperty() {
        return this.action;
    }

    public final java.lang.String getAction() {
        return this.actionProperty().get();
    }

    public final void setAction(final java.lang.String action) {
        this.actionProperty().set(action);
    }
}

Then you set the cell factory and cell value factory:

dateTimeColumn.setCellFactory(tc -> new LocalDateTimeTableCell<LogEntry>(true));
dateTimeColumn.setCellValueFactory(data -> data.getValue().timestampProperty());

Create a Table Cell like this:

public class LocalDateTimeTableCell<S> extends TableCell<S, LocalDateTime> {
    private final DateTimeFormatter myDateFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");
    private final DateTimeFormatter myDateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss a");
    private final boolean showTime;

    public LocalDateTimeTableCell(boolean showTime){
        this.showTime = showTime;
    }
    @Override
    protected void updateItem(LocalDateTime item, boolean empty) {
        super.updateItem(item, empty);
        if (item == null || empty) {
            setText(null);
            setStyle("");
        } else {
            // Format date.
            if(showTime) {
                setText(myDateTimeFormatter.format(item));
            }else {
                setText(myDateFormatter.format(item));
            }
        }
    }
}

I know this isn't exactly what you asked for with Joda time - but should give you direction.