我在我认为纯粹是 UTC 的代码中遇到了一个意外的夏令时问题。我正在使用 Java 1.6、iBatis SQL 映射器 (2.3.3) 和 Oracle XE(Oracle 10.2 的评估版)和 Oracle 瘦驱动程序。
该数据库包含一个表示电视广播时间表的表。每个“资产”(程序)都有一个开始时间和结束时间。这是相关的切片:
create table Asset
(
asset_id integer not null, -- The unique id of the Asset.
[...]
start_time timestamp, -- The start time.
end_time timestamp, -- The end time.
[...]
constraint asset_primary_key primary key (asset_id),
constraint asset_time check (end_time >= start_time)
);
asset_time
在即将到来的 2009 年 11 月 1 日星期日上午,跨越美国中央夏令时调整的程序正在触发预言机约束。
我有这个数据传输对象(日期是 java.util.Dates):
public class Asset
{
protected Long asset_id;
[...]
protected Date start_time;
protected Date end_time;
public Date getStart_time() { return start_time; }
public Date getEnd_time() { return end_time; }
public void setStart_time(Date start_time) { this.start_time = start_time; }
public void setEnd_time(Date end_time) { this.end_time = end_time; }
[...]
}
在 iBatis SQL 映射中,我有将 Asset DTO 插入 Oracle Asset 表的语句:
<insert id="Asset.insert" parameterClass="com.acme.Asset">
insert into Asset
( asset_id, [...] start_time, end_time )
values
( #asset_id#, [...] #start_time#, #end_time# )
</insert>
在 Java 方面,我已经验证我通过这个预插入断言为 iBatis 提供了正确的 UTC 日期输入,它没有被抛出:
System.err.println("Inserting asset " + program_id);
System.err.println(" "+asset.getStart_time_str()+"--"+asset.getEnd_time_str());
if ( !asset.getEnd_time().after(asset.getStart_time())) {
System.err.println("Invalid datetime range in asset.");
throw new AssertionError("Invalid datetime range in asset.");
}
就在 Oracle 约束失败之前,上面的代码打印:
Inserting asset EP011453960004
2009-11-01T06:30:00Z--2009-11-01T07:00:00Z
我在美国中部时区,格林威治标准时间 -5:00,所以这个程序从凌晨 1:30 开始,到凌晨 2:00 结束。夏令时更改在凌晨 2:00 发生,并将时钟调回凌晨 1:00。
iBatis 报告 Oracle 约束失败(已编辑):
2009-10-30 22:58:42,238 [...] Executing Statement:
insert into Asset ( asset_id, [...] start_time, end_time )
values ( ?, [...] ?, ? )
2009-10-30 22:58:42,238 [...] Parameters:
[EP011453960004, [...] 2009-11-01 01:30:00.0, 2009-11-01 01:00:00.0]
2009-10-30 22:58:42,238 [..] Types:
[java.lang.Long, [...] java.sql.Timestamp, java.sql.Timestamp]
2009-10-30 22:58:42,285 [...] - Failed with a SQLException:
--- The error occurred in com/acme/data/dao/Asset-Write.xml.
--- The error occurred while applying a parameter map.
--- Check the Asset.insert-InlineParameterMap.
--- Check the statement (update failed).
--- Cause: java.sql.SQLException: ORA-02290: check constraint (ACME.ASSET_TIME)
violated
您会注意到,在 Oracle 方面,它看到了带有夏令时调整的 start_time/end_time,因此 iBatis 映射逻辑或 Oracle 驱动程序中的某些内容没有达到我的预期。驱动是ojdbc14.jar,瘦驱动:
JDBCReadWrite.Driver = oracle.jdbc.OracleDriver
JDBCReadWrite.ConnectionURL = jdbc:oracle:thin:@localhost:1521:XE
确保此代码纯粹是 UTC 的正确方法是什么?
提前致谢!