【问题标题】:Unmarshalling JSON sql Date fields from servlet, mine gets date wrong?从 servlet 解组 JSON sql 日期字段,我的日期错误?
【发布时间】:2018-02-27 18:26:40
【问题描述】:

我正在使用 JSON 从 HttpServlet 获取数据,用于在 servlet 和 java 客户端之间共享的数据对象类定义。如果我打印出 api 调用的响应,我可以看到实例变量是正确的。然后,当我使用 Jackson 对象映射器对其进行映射并查看实例时,值是错误的,总是比响应和数据库中的日期低一天。

响应如下:

[{"coveragePK":3,"agentPK":2,"serviceCoveragePK":12,
  "coverageDate":"2018-02-27","duration":10,"remainder":1,
  "startTime":"07:30:00","query":""},
 {"coveragePK":4,"agentPK":2,"serviceCoveragePK":13,
  "coverageDate":"2018-02-27","duration":8,"remainder":2,
  "startTime":"10:00:00","query":""}]

映射后我得到:

Date: 2018-02-26 which is printed with

java.sql.Date date = coverages[i].getCoverageDate();
System.out.println("Date: " + date.toString());

如果我将 sql.Date 转换为 LocalDate,结果与预期的相同。

我使用以下内容编写覆盖范围为 ArrayList 的 json。

ObjectMapper mapper = new ObjectMapper();
String psWindows = mapper.writeValueAsString(coverages);
PrintWriter out = httpServletResponse.getWriter();
out.append(psWindows);

我用

阅读了 JSON
ObjectMapper mapper = new ObjectMapper();
CoverageDO[] coverage = mapper.readValue(foo, CoverageDO[].class);

【问题讨论】:

    标签: java json jackson objectmapper


    【解决方案1】:

    我怀疑问题出在您的时区。

    java.sql.Date 将日期存储为时间戳(自 1970 年 1 月 1 日 00:00:00 GMT 以来的时间),但是当它转换为 java.util.Date 时。尝试使用 SimpleDateFormat 来检查真实日期。

    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").parse(date);
    

    【讨论】:

    • 我从不将其转换为 java.util.date。
    【解决方案2】:

    tl;博士

    LocalDate.parse( "2018-02-27" )
    

    java.time

    java.sql.Date 类是麻烦的旧日期时间类的一部分,现在已被 java.time 类取代。

    LocalDate ld = LocalDate.parse( "2018-02-27" ) ;
    LocalTime lt = LocalTime.parse( "10:00:00" ) ;
    

    通过调用toString,使用标准ISO 8601 格式生成一个表示该日期值的字符串。

    String output = ld.toString() ;
    

    2018-02-27

    把这两个放在一起。

    LocalDateTime ldt = LocalDateTime.of( ld , lt ) ;
    

    ldt.toString(): 2018-02-27T10:00:00

    LocalDateTime 缺少任何时区概念或与 UTC 的偏移量。因此,LocalDateTime 确实代表一个时刻,不是时间轴上的一个点。它代表了大约 26-27 小时范围内潜在时刻的模糊概念。

    要确定一个实际时刻,如果您绝对确定这样的时区/偏移量是有意的,请将其放入时区(或偏移量)的上下文中。

    如果我将 sql.Date 转换为 LocalDate

    不要。再也不用java.sql.Date了。只需使用LocalDate

    如果您必须与尚未更新到 java.time 类的旧代码进行互操作,则调用添加到旧类的新转换方法。

    LocalDate ld = myJavaSqlDate.toLocalDate() ;  // From legacy class to modern class.
    java.sql.Date myJavaSqlDate = java.sql.Date.valueOf( ld ) ; // Vice-versa. From modern class to legacy class.
    

    关于java.time

    java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

    Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

    您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

    【讨论】:

    • 那么我应该将数据库中的日期作为 long 存储,然后将 ld.toEpochDay() 存储在数据库中并在任何地方使用此值。
    • @Nefarious 为什么不在数据库中使用日期时间类型来存储日期时间值?对于DATE 的标准SQL 类型,交换LocalDate 对象:myPreparedStatement.setObject( … , myLocalDate ) ;LocalDate myLocalDate = myResultSet.getObject( … , LocalDate.class ) ;
    • 我还没有真正尝试过,但我的想法是一般对象不是 sql 可比的。
    • @Nefarious JDBCJDBC drivers 的全部意义在于在Java 类型(类/对象)和数据库类型之间进行调解。我建议你研究Oracle Tutorial on JDBC
    • 我想知道 JDBC 对存储过程有何影响?如果我将任意对象存储在数据库中,则无法在存储过程中与它进行比较。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-30
    • 1970-01-01
    • 2015-05-14
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    相关资源
    最近更新 更多