正确使用org.joda.time.contrib.hibernate.PersistentDateTime与webapp配置的时区不同于db

时间:2011-09-15 05:21:37

标签: oracle hibernate spring timezone jodatime

我确信已经多次遇到这种情况,并在其他地方写过。为这篇冗长的帖子提前道歉,但我想提供尽可能多的细节。

我有一个工作站在一个时区运行JVM(在我的情况下-07:00)。我有一个Oracle数据库,配置为以UTC格式保存日期值。

我正在尝试使用具有自定义Hibernate类型的jodatime扩展名http://www.joda.org/joda-time-hibernate/,其中一个是PersistentDateTime。

以下是我的.hbm.xml中的示例。

<hibernate-mapping>
<class name="com.spp.mui.domain.MktBidHourly" table="MKTBIDHOURLY">
    <comment>Entity to represent the hourly participant bids</comment>
    <id name="bidId" type="big_decimal">
        <column name="BIDID" precision="22" scale="0" />
        <generator class="foreign">
            <param name="property">mktBid</param>
        </generator>
    </id>
    <one-to-one name="mktBid" class="com.spp.mui.domain.MktAbstractBid" constrained="true"></one-to-one>

    <property name="period" type="org.joda.time.contrib.hibernate.PersistentDateTime">
        <column name="PERIOD" length="7">
            <comment>Identifies the Period for which the bid applies.</comment>
        </column>
    </property>
    <property name="bidCurveId" type="big_decimal">
        <column name="BIDCURVEID" precision="22" scale="0">
            <comment>A database-generated unique identifier for the bid curve</comment>
        </column>
    </property>
</class>

请注意MktBidHourly中的句点字段。

因此,在为我的一个DAO(使用Spring)执行单元测试之前,我使用像Toad(for Oracle)这样的工具来插入一些数据,这些数据将在测试中查询,类似于

  

插入MKTBIDHOURLY值(33,(select to_timestamp('2011-08-03   13:00','YYYY-MM-DD HH24:MI')来自双),298384);

我的DAO中的Hibernate查询看起来有点像这样

public static final String QRY_FIND_BIDS =
        "from MktBid bid where bid.priceNodeId in (:priceNodeIdList) and bid.mktBidHourly.period in (:periodsList) and bid.mktBidType = (:bidType) and bid.participantId = (:participantId)";

 Query q = getSession().createQuery(MktQueries.QRY_FIND_BIDS);
        q.setParameterList("priceNodeIdList", priceNodeIds);
        q.setParameterList("periodsList", periods);
        q.setEntity("bidType", bidType);
        q.setBigDecimal("participantId", participantId);
        realBids = q.list();

这是测试方法

@Test
public void testFindVirtualBids() throws ParseException {
    List<MktVirtualBid> candidateBids = new ArrayList<MktVirtualBid>();
    MktBidType bidType = new MktBidType(MktBid.VIRTUAL_BID);
    candidateBids.add(data.createMktVirtualBid(new BigDecimal(LOCATION_ID_1), false, timeDispatcher.getDateTimeFromXMLDateTime("2011-08-03T13:00:00-07:00"), new BigDecimal(CURVE_ID_1)));
    candidateBids.add(data.createMktVirtualBid(new BigDecimal(LOCATION_ID_2), false, timeDispatcher.getDateTimeFromXMLDateTime("2011-08-04T13:00:00-07:00"), new BigDecimal(CURVE_ID_2)));
    List<MktVirtualBid> foundBids = dao.findVirtualBids(bidType, new BigDecimal(PARTICIPANT_ID), candidateBids);
    Assert.assertEquals(2, foundBids.size());
}

请注意timeDispatcher方法正在使用

ISODateTimeFormat.dateTimeParser().withZone(DateTimeZone.getDefault())

作为格式化程序,然后

parseDateTime(xmlDateTime).withZone(DateTimeZone.UTC)

获取DateTime。

以下是测试运行的一些示例输出(抱歉格式不佳)

  

16:22:31,729 DEBUG [AbstractBatcher]即将打开PreparedStatement(打开PreparedStatements:0,全局:0)
  16:22:31,732 DEBUG [SQL]
      选择
          mktbid0_.BIDID为BIDID5_,
          mktbid0_.BIDTYPE为BIDTYPE5_,
          mktbid0_.PARTICIPANTID为PARTICIP3_5_,
          mktbid0_.PNODEID为PNODEID5_,
          mktbid0_.USEBIDSLOPE as USEBIDSL5_5_
      从
          DEVMOI2.MKTBID mktbid0 _,
          DEVMOI2.MKTBIDHOURLY mktbidhour1_
      其中
          mktbid0_.BIDID = mktbidhour1_.BIDID
          (
              mktbid0_.PNODEID in(
                  ? ,?
              )
          )
          (
              mktbidhour1_.PERIOD in(
                  ? ,?
              )
          )
          和mktbid0_.BIDTYPE =?
          和mktbid0_.PARTICIPANTID =?休眠:
      选择
          mktbid0_.BIDID为BIDID5_,
          mktbid0_.BIDTYPE为BIDTYPE5_,
          mktbid0_.PARTICIPANTID为PARTICIP3_5_,
          mktbid0_.PNODEID为PNODEID5_,
          mktbid0_.USEBIDSLOPE as USEBIDSL5_5_
      从
          DEVMOI2.MKTBID mktbid0 _,
          DEVMOI2.MKTBIDHOURLY mktbidhour1_
      其中
          mktbid0_.BIDID = mktbidhour1_.BIDID
          (
              mktbid0_.PNODEID in(
                  ? ,?
              )
          )
          (
              mktbidhour1_.PERIOD in(
                  ? ,?
              )
          )
          和mktbid0_.BIDTYPE =?
          和mktbid0_.PARTICIPANTID =?
  16:22:31,733 TRACE [AbstractBatcher]准备声明
  16:22:31,798 TRACE [BasicBinder]绑定参数[1]为[NUMERIC] - 262235
  16:22:31,798 TRACE [BasicBinder]绑定参数[2]为[NUMERIC] - 262234
  16:22:31,799 TRACE [BasicBinder]绑定参数[3]为[TIMESTAMP] - Wed Aug 03 13:00:00 PDT 2011
  16:22:31,799 TRACE [BasicBinder]绑定参数[4]为[TIMESTAMP] - 2011年8月4日星期四13:00:00   16:22:31,801 TRACE [BasicBinder]绑定参数[5]为[VARCHAR] - D
  16:22:31,801 TRACE [BasicBinder]绑定参数[6]为[NUMERIC] - 260699

然后测试失败

  

结果:

     

测试失败:
            testFindVirtualBids(com.spp.mui.persistence.hibernate.MktBidDAOTest):expected:&lt; 2&gt;但是:&lt; 0&gt;

     

测试运行:2,失败:1,错误:0,跳过:0

为什么我的测试断言不会通过?

1 个答案:

答案 0 :(得分:0)

我自己解决了这个问题。我如何插入日期的棘手部分。我选择了另一条路线,遗憾的是我无法分享代码。我只想说我开发了一个测试基类,其中包含一个用于加载CSV文件的例程。它利用Spring的TestContext框架,特别是@BeforeTransaction带注释的方法,该方法委托给助手来处理各种String类型(例如,date,number,byte []等)。

格式化程序基本上是正确的。对于那些好奇的人,timeDispatcher的方法impl看起来像这样......

 public DateTime getDateTimeFromXMLDateTime(String xmlDateTime) {  
    if(xmlDateTime == null || "".equals(xmlDateTime)) {  
        return null;  
    } else {  
        return isoParser.parseDateTime(xmlDateTime).withZone(gmtTZ);  
    }  
}  

其中

isoParser = ISODateTimeFormat.dateTimeParser(DateTimeZone.getDefault());  

gmtTZ = DateTimeZone.UTC;