2011-08-19 9 views
12

Próbując wyjściu listę elementów w DataTable, tak:JSF convertDateTime ze strefy czasowej w elementu datatable

<t:dataTable value="#{mybean.list}" var="item"> 
     <h:column> 
      <h:outputText value="#{item.time}"> 
       <f:convertDateTime pattern="yyyy-MM-dd HH:mm:ssZ" timeZone="#{item.timeZone}" /> 
      </h:outputText> 
     </h:column> 
</t:dataTable> 

Zawsze formatuje czas w GMT. Działa zgodnie z oczekiwaniami, jeśli używam stałej łańcuchowej lub fasoli, która nie jest zmienną danych (np. "# {Mybean.timeZone}").

Odpowiedz

22

Niestety, taka jest natura tagów <f:xxx>. Kiedy widok ma zostać zbudowany, budowana jest pojedyncza instancja znacznika, w którym tworzony jest konwerter. Wszystkie jego atrybuty zostały przeczytane i ustawione tylko raz. W chwili, gdy widok został już zbudowany, #{item} zostaje rozwiązany na null (jest dostępny tylko podczas renderowania widoku), więc atrybut timeZone będzie null, a następnie domyślnie UTC. Gdy widok ma być renderowany, to samo wystąpienie konwertera zostało ponownie użyte dla każdego wiersza tabeli.

Istnieje kilka sposobów rozwiązania tego problemu. Mogę wymyślić niestandardowy konwerter lub funkcję EL. Myślę, że niestandardowy konwerter jest przecież najlepszy, ponieważ może być następnie ponownie użyty w komponentach wejściowych. Poniższy przykład kickoff powinny wypracować dla Ciebie (nullchecks i pominięty dla zwięzłość):

@FacesConverter("extendedDateTimeConverter") 
public class ExtendedDateTimeConverter extends DateTimeConverter { 

    @Override 
    public Object getAsObject(FacesContext context, UIComponent component, String value) { 
     setPattern((String) component.getAttributes().get("pattern")); 
     setTimeZone(TimeZone.getTimeZone((String) component.getAttributes().get("timeZone"))); 
     return super.getAsObject(context, component, value); 
    } 

    @Override 
    public String getAsString(FacesContext context, UIComponent component, Object value) { 
     setPattern((String) component.getAttributes().get("pattern")); 
     setTimeZone(TimeZone.getTimeZone((String) component.getAttributes().get("timeZone"))); 
     return super.getAsString(context, component, value); 
    } 

} 

który może być używany jako

<h:outputText value="#{item.time}"> 
    <f:converter converterId="extendedDateTimeConverter" /> 
    <f:attribute name="pattern" value="yyyy-MM-dd HH:mm:ssZ" /> 
    <f:attribute name="timeZone" value="#{item.timeZone}" /> 
</h:outputText> 

ten sposób strefa czasowa jest rozwiązany za każdym konwerter jest wywoływana zamiast podczas jego budowy.


Aktualizacja: the OmniFaces <o:converter> rozwiązuje dokładnie ten problem bez konieczności niestandardowego konwertera.

<h:outputText value="#{item.time}"> 
    <o:converter converterId="javax.faces.DateTime" pattern="yyyy-MM-dd HH:mm:ssZ" timeZone="#{item.timeZone}" /> 
</h:outputText> 
Powiązane problemy