Java 将SQL Server日期数据获取到Joda对象中的最佳方法?

Java 将SQL Server日期数据获取到Joda对象中的最佳方法?,java,sql-server-2008,jodatime,Java,Sql Server 2008,Jodatime,TL;DR版本:请确认(如果没有,请提供帮助)我正在将SQL Serverdatetimeoffset数据正确地导入我的Joda Time Java对象中 我正计划将数据库和java代码移动到时区感知。为了实现这一点,我已经完成了所有的工作,并且正在尝试实施最佳实践。请注意,所有代码都被视为“一次性”代码,因此我并不真正关心这里的效率;正确无误 我们的环境由一个MicrosoftSQLServer2008数据库和一个Java服务层组成,通过存储过程和SpringSimpleJDBCall访问所

TL;DR版本:请确认(如果没有,请提供帮助)我正在将SQL Server
datetimeoffset
数据正确地导入我的Joda Time Java对象中


我正计划将数据库和java代码移动到时区感知。为了实现这一点,我已经完成了所有的工作,并且正在尝试实施最佳实践。请注意,所有代码都被视为“一次性”代码,因此我并不真正关心这里的效率;正确无误

我们的环境由一个MicrosoftSQLServer2008数据库和一个Java服务层组成,通过存储过程和Spring
SimpleJDBCall
访问所有数据

提到的最佳实践之一是使用Joda时间库。由于这对我来说是新的,就像
datetimeoffset
SQL数据类型一样,我希望确保我正确地执行了这项操作(因此不会丢失任何信息)

在SQL Server内部,我创建了一个表,用于测试所有各种SQL Server get time类型函数:

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='helloworld!'。结果数据为:

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 
有一个相应的存储过程,它只需从MIKE_TEMP
执行一个
选择*,并将所有数据作为输出参数返回

访问此数据的Java代码是(为了清楚起见,仅包含“有趣的”导入):

这是通过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的部分结果,但肯定不是所有结果。我是不是错过了什么?在这种情况下,使用
java.util.Date
对象调用Joda
DateTime(Object)
ctor是否正确?我还能/应该做什么我没有做的事


谢谢

不,不是这样做的。您使用的构造函数带有
日期
,它只知道一个瞬间,并使用系统默认时区

正如BalusC所写,如果您想自己指定时区,可以将
日历
传递到
ResultSet.getTimestamp()
,但这与保存数据库中已经存在的信息不同

现在还不清楚您使用的是哪种JDBC驱动程序,您可能需要远离
SimpleJDCCall
,但Microsoft JDBC驱动程序v3.0(与
SQLServerResultSet
相同)可能会做正确的事情。鉴于您的数据类型不是真正可移植的,这意味着您的代码也不能真正可移植:(


您确实需要保留偏移量吗?如果不需要,您可能会集中精力使用“正常”JDBC调用来获取正确的瞬间,不幸的是,现在看起来它没有这样做。

如果您想完全避免
java.util.Date/Calendar
,这就是我所做的

SQL server端:

SELECT CONVERT(NVARCHAR, DateFieldName, 126) AS DateFieldIsoString
其中,
DateFieldName
是一个
datetimeoffset
字段,查询返回一个
java.lang.String

字符串
解析为Joda
DateTime

DateTime datetime = ISODateTimeFormat.dateTimeParser().withOffsetParsed()
          .parse(dateFieldAsString)

您的关键问题是
java.util.Date
不存储自定义时区信息。它始终是UTC。为了给出合适的答案,这段代码从原始JDBC中抽象了太多,但您可能需要
ResultSet#getTimestamp()
方法,其中您传递一个保存时区的
java.util.Calendar
。感谢指向MSJDBC 3.0驱动程序的指针。我们目前正在使用同一驱动程序的2.0版本,但更新版本似乎将使我们能够在java代码中本机支持
datetimeoffset
数据类型,而不会丢失i来自数据库端的信息。合理地确定这与我们要查找的非常接近。再次感谢!
DateTime datetime = ISODateTimeFormat.dateTimeParser().withOffsetParsed()
          .parse(dateFieldAsString)