【问题标题】:How to insert date/time in the UTC zone into MySQL via EclipseLink using Joda-Time?如何使用 Joda-Time 通过 EclipseLink 将 UTC 区域中的日期/时间插入 MySQL?
【发布时间】:2013-10-22 15:53:32
【问题描述】:

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

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

以下是再次将org.joda.time.DateTime 转换为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);
    }
}

convertObjectValueToDataValue()方法(第一个)中,第一个参数-objectValue收到的值是由Joda-Time在JSF转换器中转换的正确的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;

编辑: (以下 JSF 转换器与上面保持不变的 EclipseLink 转换器按预期工作 - 从唯一的 answer 到现在由 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;
    }
}

【问题讨论】:

  • UTF?也许UTC,时间戳通常已经在UTC,所以问题只是在从毫秒到字符串的转换过程中,为此检查stackoverflow.com/questions/7670355/…,同时检查正确的数据库时区设置
  • 抱歉,它是 UTC - 困打字。
  • 我无法返回 Calendar 对象。当数据被提供给数据库时,它应该返回java.sql.Timestamp。这就是 JPA 映射的工作原理。
  • 您在哪里看到数据库包含无效值?
  • 当我通过 PrimeFaces 日历输入像 02-Oct-2013 11:34:26 AM 这样的日期时,插入数据库的日期/时间与从日历中选择的日期/时间相同 - 2013-10-02 11:34:26。转换为 UTC 后应该是 2013-10-02T06:04:26.000Z。不应该吗?我错了吗?

标签: jsf timezone eclipselink converter jodatime


【解决方案1】:

您的具体问题是因为DateTime#toDate() 在转换为java.util.Date 期间未使用时区。它基本上返回new Date(millis),其中millisDateTime 实例的内部存储的纪元时间,完全符合DateTime javadoc 的描述和java.util.Date constructor 的要求。

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

从技术上讲,问题出在您的自定义 JSF 转换器中,该转换器从 String 转换为 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 实例最终将具有正确的内部纪元时间(以毫秒为单位)。

【讨论】:

  • 我有this JSF 转换器,但不幸的是,这并没有什么不同。谢谢
  • 编辑了问题本身以包含 JSF 转换器。
  • 那么您要么没有运行新的转换器,要么误解了结果,或者问题转移到了迄今为​​止提供的信息中不可见的其他地方。新的转换器应该特别修复部分 “但是当这个值被这个表达式转换时 - (DateTime) objectValue).withZone(DateTimeZone.UTC).toDate(), 它再次被评估为 2013-10-02 11 :34:26.0".
  • 两个转换器都各司其职。此行 - DateTimeFormat.forPattern("dd-MMM-yyyy hh:mm:ss aa").withZone(DateTimeZone.forTimeZone(TimeZone.getTimeZone("IST"))).parseDateTime("02-Oct-2013 11:34:26 AM") 返回 2013-10-02T11:34:26.000+05:30。这看起来很奇怪。 JSF 转换器DateTimeFormatter dateTimeFormatter=DateTimeFormat.forPattern("dd-MMM-yyyy hh:mm:ss aa");dateTimeFormatter.parseDateTime(value).withZone(DateTimeZone.UTC); 中的这两行返回02-Oct-2013 06:04:26 AM,但这在发送到MySQL 时没有任何区别。我在其他地方没有发现任何问题。
  • “古怪”的结果是正确的结果。它表示日期输入为 11:34:26,其偏移量与 IST 时区匹配(因此不是 GMT!)。那么问题显然出在 JPA/JDBC 方面。
猜你喜欢
  • 1970-01-01
  • 2014-04-20
  • 2013-10-22
  • 1970-01-01
  • 2013-01-14
  • 2013-08-18
  • 2014-01-04
  • 2010-11-22
  • 1970-01-01
相关资源
最近更新 更多