Wie verwende ich java.time.ZonedDateTime / LocalDateTime in p: calendar

Ich habe Joda Time für die Datums- / Uhrzeitmanipulation in einer Java EE-Anwendung verwendet, in der eine vom zugeordneten Client übermittelte Zeichenfolgendarstellung der Datums- / Uhrzeit mithilfe der folgenden Konvertierungsroutine konvertiert wurde, bevor sie an eine Datenbank gesendet wurde, d. H. ImgetAsObject() -Methode in einem JSF-Konverter.

org.joda.time.format.DateTimeFormatter formatter = org.joda.time.format.DateTimeFormat.forPattern("dd-MMM-yyyy hh:mm:ss a Z").withZone(DateTimeZone.UTC);
DateTime dateTime = formatter.parseDateTime("05-Jan-2016 03:04:44 PM +0530");

System.out.println(formatter.print(dateTime));

Die angegebene lokale Zeitzone ist 5 Stunden und 30 Minuten vorUTC / GMT. Daher ist die Umstellung aufUTC sollte 5 Stunden und 30 Minuten von der angegebenen Datumszeit abziehen, was mit Joda Time korrekt geschieht. Die folgende Ausgabe wird wie erwartet angezeigt.

05-Jan-2016 09:34:44 AM +0000

► Der Zeitzonenversatz+0530 anstelle von+05:30 wurde genommen, weil es von @ abhän<p:calendar>, das einen Zonenoffset in diesem Format sendet. Es scheint nicht möglich zu sein, dieses Verhalten von @ zu änder<p:calendar> (Diese Frage selbst wäre sonst nicht nötig gewesen).

Das gleiche Problem tritt jedoch auf, wenn versucht wird, die Java Time API in Java 8 zu verwenden.

java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm:ss a Z").withZone(ZoneOffset.UTC);
ZonedDateTime dateTime = ZonedDateTime.parse("05-Jan-2016 03:04:44 PM +0530", formatter);

System.out.println(formatter.format(dateTime));

Es zeigt unerwartet die folgende falsche Ausgabe an.

05-Jan-2016 03:04:44 PM +0000

Offensichtlich entspricht die umgerechnete Datums- und Uhrzeitangabe nichtUTC in das es konvertieren soll.

Damit die folgenden Änderungen richtig funktionieren, müssen sie übernommen werden.

java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm:ss a z").withZone(ZoneOffset.UTC);
ZonedDateTime dateTime = ZonedDateTime.parse("05-Jan-2016 03:04:44 PM +05:30", formatter);

System.out.println(formatter.format(dateTime));

Welche wiederum zeigt Folgendes an:

05-Jan-2016 09:34:44 AM Z

Z wurde durch @ ersetz und+0530 wurde durch @ erset+05:30.

Warum sich diese beiden APIs in dieser Hinsicht unterschiedlich verhalten, wurde in dieser Frage von ganzem Herzen ignoriert.

Welcher Mittelwegansatz kann für @ in Betracht gezogen werde<p:calendar> und Java Zeit in Java 8, um konsistent und kohärent zu arbeiten.<p:calendar> verwendet internSimpleDateFormat zusammen mitjava.util.Date?

Das nicht erfolgreiche Testszenario in JSF.

Der Konverter:

@FacesConverter("dateTimeConverter")
public class DateTimeConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value == null || value.isEmpty()) {
            return null;
        }

        try {
            return ZonedDateTime.parse(value, DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm:ss a Z").withZone(ZoneOffset.UTC));
        } catch (IllegalArgumentException | DateTimeException e) {
            throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "Message"), e);
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (value == null) {
            return "";
        }

        if (!(value instanceof ZonedDateTime)) {
            throw new ConverterException("Message");
        }

        return DateTimeFormatter.ofPattern("dd-MMM-yyyy hh:mm:ss a z").withZone(ZoneId.of("Asia/Kolkata")).format(((ZonedDateTime) value));
        // According to a time zone of a specific user.
    }
}

XHTML mit<p:calendar>.

<p:calendar  id="dateTime"
             timeZone="Asia/Kolkata"
             pattern="dd-MMM-yyyy hh:mm:ss a Z"
             value="#{bean.dateTime}"
             showOn="button"
             required="true"
             showButtonPanel="true"
             navigator="true">
    <f:converter converterId="dateTimeConverter"/>
</p:calendar>

<p:message for="dateTime"/>

<p:commandButton value="Submit" update="display" actionListener="#{bean.action}"/><br/><br/>

<h:outputText id="display" value="#{bean.dateTime}">
    <f:converter converterId="dateTimeConverter"/>
</h:outputText>

Die Zeitzone ist vollständig transparent und hängt von der aktuellen Zeitzone des Benutzers ab.

Die Bohne hat nichts anderes als eine einzelne Eigenschaft.

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

    private ZonedDateTime dateTime; // Getter and setter.
    private static final long serialVersionUID = 1L;

    public Bean() {}

    public void action() {
        // Do something.
    }
}

Dies wird auf unerwartete Weise funktionieren, wie im vorletzten Beispiel / in der Mitte der ersten drei Codefragmente gezeigt.

Speziell, wenn Sie @ eingeb05-Jan-2016 12:00:00 AM +0530, es wird wieder angezeigt05-Jan-2016 05:30:00 AM IST weil die ursprüngliche Konvertierung von05-Jan-2016 12:00:00 AM +0530 zuUTC im Konverter schlägt fehl.

Umrechnung von einer lokalen Zeitzone mit einem Versatz von+05:30 zuUTC und dann Umwandlung vonUTC zurück zu dieser Zeitzone muss natürlich die gleiche Datums- und Uhrzeitangabe wiedergeben, die über die Kalenderkomponente eingegeben wurde. Dies ist die rudimentäre Funktionalität des angegebenen Konverters.

Aktualisieren

Der JPA-Konverter konvertiert von und nachjava.sql.Timestamp undjava.time.ZonedDateTime.

import java.sql.Timestamp;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public final class JodaDateTimeConverter implements AttributeConverter<ZonedDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(ZonedDateTime dateTime) {
        return dateTime == null ? null : Timestamp.from(dateTime.toInstant());
    }

    @Override
    public ZonedDateTime convertToEntityAttribute(Timestamp timestamp) {
        return timestamp == null ? null : ZonedDateTime.ofInstant(timestamp.toInstant(), ZoneOffset.UTC);
    }
}

Antworten auf die Frage(2)

Ihre Antwort auf die Frage