Как использовать java.time.ZonedDateTime / LocalDateTime в p: calendar

Я использовал Joda Time для манипулирования датой и временем в приложении Java EE, в котором строковое представление даты-времени, представленное ассоциированным клиентом, было преобразовано с использованием следующей процедуры преобразования перед отправкой его в базу данных, т.е. вgetAsObject() метод в конвертере JSF.

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));

Местный часовой пояс на 5 часов 30 минут опережаетUTC / GMT, Поэтому преобразование вUTC следует вычесть 5 часов и 30 минут из указанной даты, что происходит правильно с использованием Joda Time. Он отображает следующий результат, как и ожидалось.

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

► Смещение часового пояса+0530 на месте+05:30 был взят, потому что это зависит от<p:calendar> который передает смещение зоны в этом формате. Кажется невозможным изменить это поведение<p:calendar> (Сам этот вопрос не был бы необходим в противном случае).

Однако то же самое нарушается при попытке использовать Java Time API в Java 8.

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));

Он неожиданно отображает следующий неверный вывод.

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

Очевидно, что преобразованная дата-время не соответствуетUTC в который предполагается конвертировать.

Для корректной работы требуются следующие изменения.

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));

Который в свою очередь отображает следующее.

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

Z был заменен наz а также+0530 был заменен на+05:30.

Почему эти два API-интерфейса ведут себя по-разному в этом вопросе, полностью игнорируется в этом вопросе.

Какой промежуточный подход можно рассмотреть для<p:calendar> и Java Time в Java 8, чтобы работать последовательно и согласованно, хотя<p:calendar> внутренне используетSimpleDateFormat вместе сjava.util.Date?

Неудачный тестовый сценарий в JSF.

Конвертер:

@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, имеющий<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>

Часовой пояс полностью прозрачно зависит от текущего часового пояса пользователя.

Боб, не имеющий ничего, кроме единственного свойства.

@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.
    }
}

Это будет работать неожиданным образом, как показано во втором последнем примере / середине в первых трех фрагментах кода.

В частности, если вы введете05-Jan-2016 12:00:00 AM +0530, будет заново05-Jan-2016 05:30:00 AM IST потому что оригинальное преобразование05-Jan-2016 12:00:00 AM +0530 вUTC в конвертере не получается.

Преобразование из местного часового пояса, смещение которого+05:30 вUTC а затем преобразование изUTC обратно в этот часовой пояс, очевидно, должно снова отображаться то же время даты, которое вводится через компонент календаря, который является элементарной функциональностью данного преобразователя.

Обновить:

Конвертер JPA, конвертирующий в и изjava.sql.Timestamp а такжеjava.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);
    }
}

Ответы на вопрос(1)

Ваш ответ на вопрос