2012-02-17 80 views
2

TL; DR版本:请确认(或者如果没有,请提供帮助),我正确地将SQL Server datetimeoffset数据正确加载到我的Joda Time Java对象中。将SQL Server日期数据导入Joda对象的最佳方法是什么?


我正在计划中,将我们的数据库和Java代码移到时区感知的位置。为了做到这一点,我一直都在this post,并试图实施最佳做法。请注意,所有代码都被认为是“丢弃”代码,所以我并不在乎效率。只是正确。

我们的环境由Microsoft SQL Server 2008数据库和Java服务层组成,我们通过存储过程和Spring访问所有数据。

提到的最佳实践之一是使用乔达时间库。由于这对我来说是新的,所以我想确保我正确地做到这一点(并且因此不会丢失任何信息)。

在SQL Server里面,我创建了一个测试表所有的不同的SQL Server获取时间型功能:

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] 

作为此服务器是在美国中部时区,我defi翘首以盼-06:00为部分的结果,但绝对不是全部是。我错过了沿途的某个地方吗?打电话给乔达DateTime(Object) ctor与java.util.Date对象在这种情况下做正确的事情?我还能做什么?我不是?

谢谢!

+1

你的关键的问题是,'java.util.Date'不存储自定义时区信息。它始终是UTC。为了给出一个合适的答案,这段代码从原始JDBC中抽象得太多了,但是您可能需要使用'ResultSet#getTimestamp()'方法来传递包含时区的'java.util.Calendar'。 – BalusC 2012-02-20 03:02:44

回答

2

不,这不是做这件事的方法。您正在使用DateTime(Object)构造函数与Date哪个只有知道一个即时的时间,并使用系统默认时区。

由于BalusC写道,你可以通过一个CalendarResultSet.getTimestamp()如果要指定自己的时区 - 但这是不一样的保护这是已经存在于数据库中的信息。

目前尚不清楚你使用的JDBC驱动程序,你可能不得不从SimpleJdbcCall移开,但微软的JDBC驱动程序V3.0具有SQLServerCallableStatement.getDateTimeOffset(同上,并为SQLServerResultSet),这大概会做正确的事。鉴于你的数据类型不是真正的便携式,这意味着你的代码不能真的是:(

你是否一定需要保留偏移量?如果不是,你可以专注于使用正确的瞬间。“正常”的JDBC调用 - 不幸的是,它看起来像它不这样做,此刻

+0

感谢指向MSJDBC 3.0驱动程序的指针。我们目前使用的驱动程序是2.0,但似乎更新版本将使我们能够在本地支持Java代码中的datetimeoffset数据类型,而不会丢失数据库端的信息。合理地确定这非常接近我们正在寻找的东西。再次感谢! – Mike 2012-02-24 16:15:17

1

如果你想避免java.util.Date/Calendar完全,这是我做了什么

SQL服务器端:

SELECT CONVERT(NVARCHAR, DateFieldName, 126) AS DateFieldIsoString 

其中DateFieldName是一个datetimeoffset字段,查询返回java.lang.String

解析String成乔达DateTime

DateTime datetime = ISODateTimeFormat.dateTimeParser().withOffsetParsed() 
      .parse(dateFieldAsString) 
相关问题