Joda time DateTime 错误地存储在数据库中

Posted

技术标签:

【中文标题】Joda time DateTime 错误地存储在数据库中【英文标题】:Joda time DateTime incorrectly stores in database 【发布时间】:2012-04-21 22:54:31 【问题描述】:

我使用 org.jadira.usertype:usertype.jodatime:1.9 将 JodaTime DateTime 字段存储到 timestamptz 列。应用服务器有 +4 时区。数据库服务器 +9 时区。 new DateTime() 导致$currentTime+1hour+9 其中+9 是时区(正确的值是$currentTime+5hours)+9)。

我还没有找到任何相关的主题。 java.util.Date 正确存储。

域对象具有以下映射属性:

static mapping = 
    dateCreated sqlType:'timestamptz'

如何正确存储 DateTime?

【问题讨论】:

【参考方案1】:

只需设置 JPA 属性:

<property name="jadira.usertype.autoRegisterUserTypes"
          value="true"/>
<property name="jadira.usertype.databaseZone"
          value="jvm"/>
<property name="jadira.usertype.javaZone"
          value="jvm"/>

【讨论】:

这个放在什么文件里? @dgrant 在您的 persistence.xml 文件中 有没有办法在没有 XML 文件的情况下做到这一点?到目前为止,我的项目正在使用纯注释进行配置...【参考方案2】:

我有同样的问题。在配置中指定 app 和 db 区域解决了这个问题。

            <prop key="jadira.usertype.autoRegisterUserTypes">true</prop>
            <prop key="jadira.usertype.databaseZone">America/Los_Angeles</prop>
            <prop key="jadira.usertype.javaZone">America/Los_Angeles</prop>

【讨论】:

这个放在什么文件里?【参考方案3】:

好的。我花了8个小时来解决这个问题。如果您使用usertype 项目来持久化JodaTime,则必须将PersistentDateTime 类的databaseZone 属性设置为等于当前应用程序服务器时区(不是数据库!)。

但最好使用official hibernate support。它解决了开箱即用的问题,因为它使用java.utl.Date 持久化DateTimejava.util.Date 默认正确持久化

【讨论】:

官方的hibernate支持没有扩展到Hibernate 4.0。 :-( 你需要使用用户类型。【参考方案4】:

尝试使用 -Duser.timezone=UTC 启动 JVM 到 JAVA_OPTS,这样时间就在一个区域中,然后您可以对其进行操作以将其转换为您所在的位置。

【讨论】:

这是一个很好的方法 - 但请注意,如果您已经将日期存储在数据库中的另一个时区,则不能这样做。换句话说,对于新项目没有问题,但对于那些有现有数据的项目要非常非常谨慎。【参考方案5】:

费多尔,

我是否正确假设您使用的是 Oracle TIMESTAMP WITH TIME ZONE 列?由于数据库之间对 JDBC 的处理方式不同,用户类型还不支持这种类型(即使用 TIME ZONE),尽管该项目很乐意接受补丁。

这里有一些关于 Oracle 的很好的讨论:http://puretech.paawak.com/2010/11/02/how-to-handle-oracle-timestamp-with-timezone-from-java/

【讨论】:

我们使用的是 PostgreSQL timestamptz【参考方案6】:

我通过创建其他 PersistentDateTime extends AbstractVersionableUserType 解决了这个问题。

import java.sql.Timestamp;

import org.hibernate.SessionFactory;
import org.hibernate.usertype.ParameterizedType;
import org.jadira.usertype.dateandtime.joda.columnmapper.TimestampColumnDateTimeMapper;
import org.jadira.usertype.spi.shared.AbstractVersionableUserType;
import org.jadira.usertype.spi.shared.IntegratorConfiguredType;
import org.joda.time.DateTime;

public class PersistentDateTime extends AbstractVersionableUserType<DateTime, Timestamp, TimestampColumnDateTimeMapper> implements ParameterizedType, IntegratorConfiguredType 

@Override
public int compare(Object o1, Object o2) 
    return ((DateTime) o1).compareTo((DateTime) o2);


@Override
public void applyConfiguration(SessionFactory sessionFactory) 

    super.applyConfiguration(sessionFactory);

    TimestampColumnDateTimeMapper columnMapper = (TimestampColumnDateTimeMapper) getColumnMapper();
    columnMapper.setDatabaseZone(null);
    columnMapper.setJavaZone(null);


【讨论】:

【参考方案7】:

只是针对 Spring Boot 用户的更新。我能够做到以下几点:

spring.jpa.properties.jadira.usertype:
  autoRegisterUserTypes: true
  databaseZone: jvm
  javaZone: jvm

我把它放在我的application.yaml 文件中。

【讨论】:

以上是关于Joda time DateTime 错误地存储在数据库中的主要内容,如果未能解决你的问题,请参考以下文章

org.joda.time.DateTime 日期格式

使用 Jackson 进行 DateTime 反序列化的默认时区(Joda-Time 模块)

我如何判断一个 joda-time DateTime 对象是不是在另一个对象的 4 小时内?

这是joda time中的错误吗?处理非常古老(0000 年)的即时/负纪元

MySQL DATETIME 精度(joda-time、Hibernate、org.jadira.usertype、hbm2ddl)

杰克逊未能将字符串反序列化为 Joda-Time