I’m sure this has been encountered many times over, and written about elsewhere. Apologies in advance for the long-winded post, but I wanted to provide as much detail as I could up front.
I have a workstation running the JVM in one timezone (in my case -07:00). I have an Oracle database configured to persist date values in UTC.
I am attempting to use jodatime extension, http://www.joda.org/joda-time-hibernate/, that has custom Hibernate types, one of which is PersistentDateTime.
Here is a sample from my .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>
Note the period field in MktBidHourly.
So before executing a unit test for one of my DAOs (using Spring), I use a tool like Toad (for Oracle), to insert some data, that will be queried in the test, something like
insert into MKTBIDHOURLY values (33, (select to_timestamp(‘2011-08-03
13:00’, ‘YYYY-MM-DD HH24:MI’) from dual), 298384);
The Hibernate query in my DAO looks a little like this
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();
Here’s the test method
@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());
}
Note the timeDispatcher method is using
ISODateTimeFormat.dateTimeParser().withZone(DateTimeZone.getDefault())
as formatter, and then
parseDateTime(xmlDateTime).withZone(DateTimeZone.UTC)
to obtain a DateTime.
Here’s some sample output from a test run (sorry for the poor formatting)
16:22:31,729 DEBUG [AbstractBatcher] about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
16:22:31,732 DEBUG [SQL]
select
mktbid0_.BIDID as BIDID5_,
mktbid0_.BIDTYPE as BIDTYPE5_,
mktbid0_.PARTICIPANTID as PARTICIP3_5_,
mktbid0_.PNODEID as PNODEID5_,
mktbid0_.USEBIDSLOPE as USEBIDSL5_5_
from
DEVMOI2.MKTBID mktbid0_,
DEVMOI2.MKTBIDHOURLY mktbidhour1_
where
mktbid0_.BIDID=mktbidhour1_.BIDID
and (
mktbid0_.PNODEID in (
? , ?
)
)
and (
mktbidhour1_.PERIOD in (
? , ?
)
)
and mktbid0_.BIDTYPE=?
and mktbid0_.PARTICIPANTID=? Hibernate:
select
mktbid0_.BIDID as BIDID5_,
mktbid0_.BIDTYPE as BIDTYPE5_,
mktbid0_.PARTICIPANTID as PARTICIP3_5_,
mktbid0_.PNODEID as PNODEID5_,
mktbid0_.USEBIDSLOPE as USEBIDSL5_5_
from
DEVMOI2.MKTBID mktbid0_,
DEVMOI2.MKTBIDHOURLY mktbidhour1_
where
mktbid0_.BIDID=mktbidhour1_.BIDID
and (
mktbid0_.PNODEID in (
? , ?
)
)
and (
mktbidhour1_.PERIOD in (
? , ?
)
)
and mktbid0_.BIDTYPE=?
and mktbid0_.PARTICIPANTID=?
16:22:31,733 TRACE [AbstractBatcher] preparing statement
16:22:31,798 TRACE [BasicBinder] binding parameter [1] as [NUMERIC] – 262235
16:22:31,798 TRACE [BasicBinder] binding parameter [2] as [NUMERIC] – 262234
16:22:31,799 TRACE [BasicBinder] binding parameter [3] as [TIMESTAMP] – Wed Aug 03 13:00:00 PDT 2011
16:22:31,799 TRACE [BasicBinder] binding parameter [4] as [TIMESTAMP] – Thu Aug 04 13:00:00 PDT 2011
16:22:31,801 TRACE [BasicBinder] binding parameter [5] as [VARCHAR] – D
16:22:31,801 TRACE [BasicBinder] binding parameter [6] as [NUMERIC] – 260699
and then the test fails
Results :
Failed tests:
testFindVirtualBids(com.spp.mui.persistence.hibernate.MktBidDAOTest): expected:<2> but was:<0>Tests run: 2, Failures: 1, Errors: 0, Skipped: 0
Why won’t my test’s assertion pass?
I solved this myself. The tricky part in how I was inserting dates. I opted for another route, which unfortunately I cannot share the code for. Suffice it to say I developed a test base class with a routine for loading in CSV files. It leverages Spring’s TestContext framework, particularly an @BeforeTransaction annotated method which delegates to helpers to deal with various String types (e.g., date, number, byte[], etc).
The formatter is fundamentally correct. For those who are curious The timeDispatcher’s method impl looks like this…
where
and