3

When I try to use the Primefaces datatable to display dates, some of them are displayed one day earlier. This is what it should be (shown by the Netbeans debug) and this is what displayed by Firefox.

The JSF page is:

    <h:body>
    <h:form>
        <p:outputLabel styleClass="header-calendar">From Date: </p:outputLabel>
        <p:calendar id="fromDate" value="#{datedCarFilterView.fromDate}" pattern="dd MM yyyy"  readonlyInput="true" maxdate="#{datedCarFilterView.currentDate}">
            <p:ajax event="dateSelect" update="viewDataTable" onstart="PF('vtWidget').clearFilters()"/>
        </p:calendar><br/>   
        <p:dataTable var="car" value="#{datedCarFilterView.cars}" id="viewDataTable" widgetVar="vtWidget">

            <p:column headerText="ID">
                <h:outputText value="#{car.id}" />
            </p:column>
            <p:column filterBy="#{car.color}" headerText="Color" filterMatchMode="contains">
                <h:outputText value="#{car.color}" />
            </p:column>    
            <p:column headerText="Date">
                <h:outputText value="#{car.date}">
                    <f:convertDateTime pattern="dd-MMM-yyyy" />
                </h:outputText>
            </p:column>                  
        </p:dataTable>
    </h:form>
</h:body>

The backing beans etc. are:

@ManagedBean(name = "datedCarFilterView") @ViewScoped public class DatedCarFilterView implements Serializable {

private static final long serialVersionUID = 978770613134439198L;

private Date fromDate;

private List<DatedCar> allCars;
private final List<DatedCar> cars = new ArrayList<>();

@ManagedProperty("#{datedCarService}")
private DatedCarService service;

@PostConstruct
public void init() {
    allCars = service.createCars(100);
    fromDate = new Date(getCurrentDate().getTime() - 1000 * 3600 * 24 * 3);
    refreshCarList();
}

public void setService(DatedCarService service) {
    this.service = service;
}

public List<DatedCar> getCars() {
    return cars;
}

public Date getFromDate() {
    return fromDate;
}

public void setFromDate(Date fromDate) {
    this.fromDate = fromDate;
    refreshCarList();
}

private void refreshCarList() {
    cars.clear();
    for (DatedCar car : allCars) {
        if (car.getDate().getTime() > fromDate.getTime()) {
            cars.add(car);
        }
    }
}

public Date getCurrentDate() {
    return new Date();
}}


@ManagedBean(name = "datedCarService") @ApplicationScoped public class DatedCarService implements Serializable {

private static final long serialVersionUID = 787505400128748931L;

private final static String[] colors;

static {
    colors = new String[10];
    colors[0] = "Black";
    colors[1] = "White";
    colors[2] = "Green";
    colors[3] = "Red";
    colors[4] = "Blue";
    colors[5] = "Orange";
    colors[6] = "Silver";
    colors[7] = "Yellow";
    colors[8] = "Brown";
    colors[9] = "Maroon";
}


  public List<DatedCar> createCars(int size) {
    List<DatedCar> list = new ArrayList<>();
    for(int i = 0 ; i < size ; i++) {
        list.add(new DatedCar(getRandomId(), getRandomDate(), getRandomColor()));
    }

    return list;
}

private String getRandomId() {
    return UUID.randomUUID().toString().substring(0, 8);
}

private Date getRandomDate() {

    long time = new Date().getTime();

    int hours = (int) (Math.random() * 360); 

    return new Date( time - hours*3600*1000);
}  

private String getRandomColor() {
    return colors[(int) (Math.random() * 10)];
}    

public List<String> getColors() {
    return Arrays.asList(colors);
} }   


public class DatedCar implements Serializable {

private static final long serialVersionUID = 157675587142381235L;    

private String id;
private Date date;
private String color;

public DatedCar() {
}

public DatedCar(String id, Date date, String color) {
    this.id = id;
    this.date = date;
    this.color = color;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public Date getDate() {
    return date;
}

public void setDate(Date date) {
    this.date = date;
}

public String getColor() {
    return color;
}

public void setColor(String color) {
    this.color = color;
}

@Override
public String toString() {
    return "DatedCar{" + "id=" + id + '}';
}

@Override
public int hashCode() {
    int hash = 7;
    hash = 41 * hash + Objects.hashCode(this.id);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final DatedCar other = (DatedCar) obj;
    return Objects.equals(this.id, other.id);
} }

I am using JSF 2.2, Primefaces 5.2 and Glassfish 4.1.

Thanks in advance.

cbangor
  • 140
  • 1
  • 12

1 Answers1

2

It looks like a timezone issue.
Dates in Java should use UTC time under the hood and translate it into the appropriate timezone which is determined by your local machine.

Your date is something like 18-Oct-2015 at 00:23 in +0100 and you're probably getting the 17th displayed because it's translating the date to into UTC (or it's translating UTC into -0100 or another similar combination). This appears to put the date back one day: 17-OCT-2015 23:23.

Try printing your date, executing the following line ,creating the date object again and then re-printing.

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

Another thing you may want to do is take away your formatting of the date in the html. i.e. delete this line

<f:convertDateTime pattern="dd-MMM-yyyy" />

So that you can see the time value of the incorrect date.

Best of luck, Ryan

  • 1
    Ryan, Great answer, thanks. I forgot the summer time. The display without the converter still does not match the one with the converter. But I know the reason now. Best regards. – cbangor Oct 20 '15 at 11:06
  • When I last had this problem I got my dates from a database and the JDBC methods getDate, getTime and getTimestamp all take a timezone as an argument so I always explicitly pass these methods the UTC Timezone. Some people use `new Date(oldDate.toString())` as a workaround too. Some combination will work. – Ryan Hancock Oct 20 '15 at 11:10
  • 1
    I have got a workaround which is similar to the code new Date(oldDate.toString()). Your suggestion to pass methods explicitly is better. Thanks again. – cbangor Oct 20 '15 at 12:57