如何使用 Joda-Time 通过 EclipseLink 将 UTC 区域中的日期/时间插入 MySQL?

2023-11-25

我需要将 UTC 区域中的日期/时间存储到 MySQL 数据库(DATETIME 类型列)中。当用户输入日期时,它首先被转换为org.joda.time.DateTime通过 JSF 转换器。

在将此日期插入 MySQL 数据库之前,需要再次将其转换为java.util.Date- 感谢 EclipseLink。

下面是再次转换器的转换器org.joda.time.DateTime to java.util.Date尽管实际上并不需要看到这个转换器。

package joda.converter;

import java.util.Date;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.converters.Converter;
import org.eclipse.persistence.sessions.Session;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

public final class JodaDateTimeConverter implements Converter
{
    private static final long serialVersionUID = 1L;

    @Override
    public Object convertObjectValueToDataValue(Object objectValue, Session session)
    {
        return objectValue instanceof DateTime?((DateTime) objectValue).withZone(DateTimeZone.UTC).toDate():null;
    }

    @Override
    public Object convertDataValueToObjectValue(Object dataValue, Session session)
    {
        return dataValue instanceof Date?new DateTime((Date) dataValue):null;
    }

    @Override
    public boolean isMutable()
    {
        return true;
    }

    @Override
    public void initialize(DatabaseMapping databaseMapping, Session session)
    {
        databaseMapping.getField().setType(java.util.Date.class);
    }
}

In the convertObjectValueToDataValue()方法(第一个),第一个参数的值 -objectValue收到的是 JSF 转换器中 Joda-Time 转换的正确 UTC 日期/时间。

例如,如果我输入一个日期 -02-Oct-2013 11:34:26 AM那么,值objectValue将会 -2013-10-02T06:04:26.000Z。应将该日期/时间插入数据库中。

但是当这个值被这个表达式转换时 -(DateTime) objectValue).withZone(DateTimeZone.UTC).toDate(),再次评估为2013-10-02 11:34:26.0并且该值提供给数据库是不正确的。

无论如何,如何将 UTC 区域设置为(DateTime) objectValue).withZone(DateTimeZone.UTC).toDate()?


类型的属性org.joda.time.DateTime在模型类中指定如下。

@Column(name = "discount_start_date", columnDefinition = "DATETIME")
@Converter(name = "dateTimeConverter", converterClass = JodaDateTimeConverter.class)
@Convert("dateTimeConverter")
private DateTime discountStartDate;

EDIT: (The following JSF converter works as expected along with the EclipseLink converter above which remains intact - from the only answer until now by BalusC)

这是我的 JSF 转换器。

package converter;

import java.util.TimeZone;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import util.Utility;

@ManagedBean
@RequestScoped
public final class DateTimeConverter implements Converter
{
    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value)
    {
        DateTime dateTime=null;

        try
        {
            dateTime = DateTimeFormat.forPattern("dd-MMM-yyyy hh:mm:ss aa").withZone(DateTimeZone.forTimeZone(TimeZone.getTimeZone("IST"))).parseDateTime(value);
        }
        catch (IllegalArgumentException e)
        {
            throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "", Utility.getMessage("datetime.converter.error", DateTimeFormat.forPattern("dd-MMM-yyyy hh:mm:ss aa").print(DateTime.now().withZone(DateTimeZone.forID("Asia/Kolkata"))))), e);
        }
        catch(UnsupportedOperationException e)
        {
            throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "", Utility.getMessage("datetime.converter.error", DateTimeFormat.forPattern("dd-MMM-yyyy hh:mm:ss aa").print(DateTime.now().withZone(DateTimeZone.forID("Asia/Kolkata"))))), e);
        }
        return dateTime;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value)
    {
        DateTimeFormatter dateTimeFormatter=DateTimeFormat.forPattern("dd-MMM-yyyy hh:mm:ss aa").withZone(DateTimeZone.forID("Asia/Kolkata")); //This zone will be tackled/handled later from the database to display.              
        return value instanceof DateTime?dateTimeFormatter.print((DateTime)value):null;
    }
}

你的具体问题是因为DateTime#toDate()在转换期间不使用时区java.util.Date。基本上就返回了new Date(millis)其中millis是内部存储的纪元时间DateTime实例,完全按照描述DateTime javadoc并要求java.util.Date构造函数.

换句话说,withZone(DateTimeZone.UTC)部分在这里完全没有影响。该代码的行为与该部分不存在时完全相同。这就解释了为什么您最终会得到最初输入的时间。

从技术上讲,问题出在您的自定义 JSF 转换器中,该转换器从String to DateTime。该转换器显然没有考虑时区,并假设输入已经在 GMT 时区(默认情况下)。必须指示转换器输入处于 IST 时区。如果您使用的是标准java.util.Date具有标准 JSF 的属性<f:convertDateTime>,那么你可以通过设置它来解决它timeZone归因于IST.

<h:inputText value="#{bean.date}">
    <f:convertDateTime pattern="dd-MMM-yyyy hh:mm:ss a" locale="en" timeZone="IST" />
</h:inputText>

您的自定义 JSF 转换器应该在幕后执行完全相同的操作:告诉 API 所提供的String位于 IST 时区,而不是让它假设它已经位于 GMT 时区。您没有在任何地方显示自定义 JSF 转换器,因此很难提供准确的答案,但它应该归结为以下启动示例:

String inputDateString = "02-Oct-2013 11:34:26 AM";
String inputDatePattern = "dd-MMM-yyyy hh:mm:ss a";
TimeZone inputTimeZone = TimeZone.getTimeZone("IST");

DateTime dateTime = DateTimeFormat
    .forPattern(inputDatePattern)
    .withZone(DateTimeZone.forTimeZone(inputTimeZone))
    .parseDateTime(inputDateString);

所结果的DateTime实例最终将具有正确的内部纪元时间(以毫秒为单位)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Joda-Time 通过 EclipseLink 将 UTC 区域中的日期/时间插入 MySQL? 的相关文章