TL; DR版本:请确认(如果没有,请提供帮助)我正确地将SQL Server datetimeoffset
数据存入我的Joda Time Java对象。
我正在计划将数据库和Java代码移动到时区。为了实现这一目标,我已经全身心地this post并尝试实施最佳实践。请注意,所有代码都被视为“丢弃”代码,所以我并不关心这里的效率;只是正确性。
我们的环境由Microsoft SQL Server 2008数据库和Java服务层组成,我们通过存储过程和Spring SimpleJdbcCall
访问所有数据。
提到的最佳做法之一是使用Joda Time库。由于这对我来说是新的,因为datetimeoffset
SQL数据类型,我想确保我正确地执行此操作(因此不会丢失任何信息。)
在SQL Server内部,我创建了一个表,用于测试所有各种SQL Server get-time-type函数:
CREATE TABLE MIKE_TEMP (
ID INT NOT NULL IDENTITY,
BLAH NVARCHAR(255),
DT_GET_DATE DATETIME DEFAULT GETDATE() NOT NULL,
DT_GET_UTC_DATE DATETIME DEFAULT GETUTCDATE() NOT NULL,
DT_SYS_DATE_TIME DATETIME DEFAULT sysdatetime() NOT NULL,
DT_SYS_UTC_DATE_TIME DATETIME DEFAULT sysutcdatetime() NOT NULL,
DT_SYS_DATE_TIME_OFFSET DATETIME DEFAULT sysdatetimeoffset() NOT NULL,
DTO_GET_DATE DATETIMEOFFSET DEFAULT GETDATE() NOT NULL,
DTO_GET_UTC_DATE DATETIMEOFFSET DEFAULT GETUTCDATE() NOT NULL,
DTO_SYS_DATE_TIME DATETIMEOFFSET DEFAULT sysdatetime() NOT NULL,
DTO_SYS_UTC_DATE_TIME DATETIMEOFFSET DEFAULT sysutcdatetime() NOT NULL,
DTO_SYS_DATE_TIME_OFFSET DATETIMEOFFSET DEFAULT sysdatetimeoffset() NOT NULL
);
在此表中,我添加了一个值blah = 'Hello World!'
。结果数据是:
ID BLAH DT_GET_DATE DT_GET_UTC_DATE DT_SYS_DATE_TIME DT_SYS_UTC_DATE_TIME DT_SYS_DATE_TIME_OFFSET DTO_GET_DATE DTO_GET_UTC_DATE DTO_SYS_DATE_TIME DTO_SYS_UTC_DATE_TIME DTO_SYS_DATE_TIME_OFFSET
-- ------------ ------------------- ------------------- ------------------- -------------------- ----------------------- ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- ----------------------------------
1 Hello World! 2012-02-15 08:58:41 2012-02-15 14:58:41 2012-02-15 08:58:41 2012-02-15 14:58:41 2012-02-15 08:58:41 2012-02-15 08:58:41.6000000 +00:00 2012-02-15 14:58:41.6000000 +00:00 2012-02-15 08:58:41.6005458 +00:00 2012-02-15 14:58:41.6005458 +00:00 2012-02-15 08:58:41.6005458 -06:00
有一个相应的存储过程只执行select * from MIKE_TEMP
并返回所有数据作为输出参数。
访问此数据的Java代码(为清晰起见,仅包含“有趣的”导入):
import org.joda.time.DateTime;
import java.util.Date;
@Component
public class MikeTempDaoImpl {
private static final Logger logger = LoggerFactory.getLogger(MikeTempDaoImpl.class);
private DataSource dataSource;
@Autowired
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public DataSource getDataSource() {
return dataSource;
}
public MikeVTemp getMikeTemp() {
SimpleJdbcCall data = new SimpleJdbcCall(getDataSource());
data.withProcedureName("get_MIKE_TEMP");
data.withoutProcedureColumnMetaDataAccess();
data.declareParameters(
new SqlOutParameter("ID", Types.INTEGER),
new SqlOutParameter("BLAH", Types.NVARCHAR),
new SqlOutParameter("DT_GET_DATE", Types.TIMESTAMP),
new SqlOutParameter("DT_GET_UTC_DATE", Types.TIMESTAMP),
new SqlOutParameter("DT_SYS_DATE_TIME", Types.TIMESTAMP),
new SqlOutParameter("DT_SYS_UTC_DATE_TIME", Types.TIMESTAMP),
new SqlOutParameter("DT_SYS_DATE_TIME_OFFSET", Types.TIMESTAMP),
new SqlOutParameter("DTO_GET_DATE", Types.TIMESTAMP),
new SqlOutParameter("DTO_GET_UTC_DATE", Types.TIMESTAMP),
new SqlOutParameter("DTO_SYS_DATE_TIME", Types.TIMESTAMP),
new SqlOutParameter("DTO_SYS_UTC_DATE_TIME", Types.TIMESTAMP),
new SqlOutParameter("DTO_SYS_DATE_TIME_OFFSET", Types.TIMESTAMP)
);
Map out;
try {
out = data.execute();
} catch (Exception ex) {
logger.error(ex.getMessage());
}
int id = (Integer) out.get("ID");
String blah = (String) out.get("BLAH");
DateTime dtGetDate = new DateTime((Date) out.get("DT_GET_DATE"));
DateTime dtGetUtcDate = new DateTime((Date) out.get("DT_GET_UTC_DATE"));
DateTime dtSysDateTime = new DateTime((Date) out.get("DT_SYS_DATE_TIME"));
DateTime dtSysUtcDateTime = new DateTime((Date) out.get("DT_SYS_UTC_DATE_TIME"));
DateTime dtSysDateTimeOffset = new DateTime((Date) out.get("DT_SYS_DATE_TIME_OFFSET"));
DateTime dtoGetDate = new DateTime((Date) out.get("DTO_GET_DATE"));
DateTime dtoGetUtcDate = new DateTime((Date) out.get("DTO_GET_UTC_DATE"));
DateTime dtoSysDateTime = new DateTime((Date) out.get("DTO_SYS_DATE_TIME"));
DateTime dtoSysUtcDateTime = new DateTime((Date) out.get("DTO_SYS_UTC_DATE_TIME"));
DateTime dtoSysDateTimeOffset = new DateTime((Date) out.get("DTO_SYS_DATE_TIME_OFFSET"));
MikeTemp mt = new MikeTemp.Builder()
.id(id)
.blah(blah)
.dtGetDate(dtGetDate)
.dtGetUtcDate(dtGetUtcDate)
.dtSysDateTime(dtSysDateTime)
.dtSysUtcDateTime(dtSysUtcDateTime)
.dtSysDateTimeOffset(dtSysDateTimeOffset)
.dtoGetDate(dtoGetDate)
.dtoGetUtcDate(dtoGetUtcDate)
.dtoSysDateTime(dtoSysDateTime)
.dtoSysUtcDateTime(dtoSysUtcDateTime)
.dtoSysDateTimeOffset(dtoSysDateTimeOffset)
.build();
System.out.println("id = [" + mt.getId() + "]");
System.out.println("blah = [" + mt.getBlah() + "]");
System.out.println("dtGetDate = [" + mt.getDtGetDate() + "]");
System.out.println("dtGetUtcDate = [" + mt.getDtGetUtcDate() + "]");
System.out.println("dtSysDateTime = [" + mt.getDtSysDateTime() + "]");
System.out.println("dtSysUtcDateTime = [" + mt.getDtSysUtcDateTime() + "]");
System.out.println("dtSysDateTimeOffset = [" + mt.getDtSysDateTimeOffset() + "]");
System.out.println("dtoGetDate = [" + mt.getDtoGetDate() + "]");
System.out.println("dtoGetUtcDate = [" + mt.getDtoGetUtcDate() + "]");
System.out.println("dtoSysDateTime = [" + mt.getDtoSysDateTime() + "]");
System.out.println("dtoSysUtcDateTime = [" + mt.getDtoSysUtcDateTime() + "]");
System.out.println("dtoSysDateTimeOffset = [" + mt.getDtoSysDateTimeOffset() + "]");
return mvt;
}
}
这是通过JUnit测试来实现的:
@Test
public void testDateData() throws Exception {
MikeTemp mt = dao.getMikeTemp();
assertNotNull("MT should not be null, but it is.", mt);
assertEquals(1, mt.getId());
assertEquals("Hello World!", mt.getBlah());
}
所有println的结果都是:
id = [1]
blah = [Hello World!]
dtGetDate = [2012-02-15T08:58:41.577-06:00]
dtGetUtcDate = [2012-02-15T14:58:41.577-06:00]
dtSysDateTime = [2012-02-15T08:58:41.580-06:00]
dtSysUtcDateTime = [2012-02-15T14:58:41.600-06:00]
dtSysDateTimeOffset = [2012-02-15T08:58:41.600-06:00]
dtoGetDate = [2012-02-15T08:58:41.600-06:00]
dtoGetUtcDate = [2012-02-15T14:58:41.600-06:00]
dtoSysDateTime = [2012-02-15T08:58:41.600-06:00]
dtoSysUtcDateTime = [2012-02-15T14:58:41.600-06:00]
dtoSysDateTimeOffset = [2012-02-15T08:58:41.600-06:00]
由于此服务器位于美国中部时区,我绝对希望看到一些结果的-06:00,但绝对不是所有他们。我在路上的某个地方错过了什么吗?在这种情况下,使用DateTime(Object)
对象调用Joda java.util.Date
ctor是否正确?还有什么可以/我应该做什么,我不是?
谢谢!
答案 0 :(得分:2)
不,这不是这样做的方法。您正在使用DateTime(Object)
构造函数,其中Date
仅 知道即时,并使用系统默认时区。
正如BalusC所写,如果您想自己指定时区,可以将Calendar
传递给ResultSet.getTimestamp()
- 但这与保留已经存在的信息不同存在于数据库中。
目前尚不清楚您正在使用哪个JDBC驱动程序,并且您可能不得不离开SimpleJdbcCall
,但Microsoft JDBC驱动程序v3.0具有SQLServerCallableStatement.getDateTimeOffset
(同上{{} 1}})这可能是正确的做法。鉴于您的数据类型不是真正可移植的,这意味着您的代码实际上不是:(
你肯定需要保留偏移吗?如果没有,你可能会集中精力使用“普通”JDBC调用来获得正确的瞬间 - 不幸的是,它现在看起来并没有这样做。
答案 1 :(得分:1)
如果你想完全避免java.util.Date/Calendar
,那就是我所做的
SQL服务器端:
SELECT CONVERT(NVARCHAR, DateFieldName, 126) AS DateFieldIsoString
其中DateFieldName
是datetimeoffset
字段,查询返回java.lang.String
将String
解析为Joda DateTime
:
DateTime datetime = ISODateTimeFormat.dateTimeParser().withOffsetParsed()
.parse(dateFieldAsString)