将Jackson时区设置为日期反序列化

Mik*_*e G 40 json spring-mvc jackson

我正在使用Jackson(通过Spring MVC Annotations)将字段反序列化为java.util.Date来自JSON.POST看起来像 - {"enrollDate":"2011-09-28T00:00:00.000Z"},但是当对象由Spring&Jackson创建时,它将日期设置为"2011-09-27 20:00:00".

如何在杰克逊设置合适的时区? 或者,如果这不是问题,我如何从JSON消息发送EST?

使用Javascript/jQuery的:

var personDataView = { enrollDate : new Date($("#enrollDate").val()), 
                       //...other members
                      };


$.postJSON('/some/path/', personDataView, function(data){
    //... handle the response here

});
Run Code Online (Sandbox Code Playgroud)

JSON消息:

{"enrollDate":"2011-09-28T00:00:00.000Z"}

弹簧控制器:

@RequestMapping(value="/", method=RequestMethod.POST)
public @ResponseBody String saveProfile(@RequestBody personDataView persondataView, HttpServletRequest request)
{
        //...dataView has a java.util.Date enrollDate field
        //...other code
}
Run Code Online (Sandbox Code Playgroud)

Oli*_*ain 44

在Jackson 2+中,您还可以使用@JsonFormat注释:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone="America/Phoenix")
private Date date;
Run Code Online (Sandbox Code Playgroud)

  • @JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ", timezone="US/Arizona") (2认同)

SiC*_*iCN 15

如果你真的希望杰克逊用另一个时区返回一个比UTC更早的日期(而且我自己有几个很好的论据,特别是当一些客户没有得到时区部分时)那么我通常会做:

ObjectMapper mapper = new ObjectMapper();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
dateFormat.setTimeZone(TimeZone.getTimeZone("CET"));
mapper.getSerializationConfig().setDateFormat(dateFormat);
// ... etc
Run Code Online (Sandbox Code Playgroud)

它对那些了解时区-p的人没有任何负面影响

  • 似乎mapper.getSerializationConfig().setDateFormat(dateFormat)现在已弃用,新的​​方法是mapper.setDateFormat(dateFormat) (14认同)

小智 7

您是否在application.properties中尝试过此操作?

spring.jackson.time-zone= # Time zone used when formatting dates. For instance `America/Los_Angeles`
Run Code Online (Sandbox Code Playgroud)


Luk*_*szH 7

看起来旧的答案对于旧的 Jackson 版本来说很好,但由于objectMapperhas 方法setTimeZone(tz),在 dateFormat 上设置时区完全被忽略。

如何在 Jackson 版本 2.11.0 中正确设置时区到 ObjectMapper:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setTimeZone(TimeZone.getTimeZone("Europe/Warsaw"));
Run Code Online (Sandbox Code Playgroud)

完整示例

  @Test
  void test() throws Exception {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.findAndRegisterModules();
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    JavaTimeModule module = new JavaTimeModule();
    objectMapper.registerModule(module);
    objectMapper.setTimeZone(TimeZone.getTimeZone("Europe/Warsaw"));

    ZonedDateTime now = ZonedDateTime.now();
    String converted = objectMapper.writeValueAsString(now);

    ZonedDateTime restored = objectMapper.readValue(converted, ZonedDateTime.class);
    System.out.println("serialized: " + now);
    System.out.println("converted: " + converted);
    System.out.println("restored: " + restored);

    Assertions.assertThat(now).isEqualTo(restored);
  }
`
Run Code Online (Sandbox Code Playgroud)

  • 我使用相同的方法,但设置 JVM 时区 mapper.setTimeZone(TimeZone.getDefault()),以避免对特定时区进行硬编码。 (2认同)

whi*_*der 5

我正在使用 Jackson 1.9.7,我发现执行以下操作并不能解决我的序列化/反序列化时区问题:

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZ");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
objectMapper.setDateFormat(dateFormat);
Run Code Online (Sandbox Code Playgroud)

我在 JSON 消息中得到的不是“2014-02-13T20:09:09.859Z”,而是“2014-02-13T08:09:09.859+0000”,这显然是不正确的。我没有时间单步执行 Jackson 库源代码来弄清楚为什么会发生这种情况,但是我发现如果我只是将 Jackson 提供的ISO8601DateFormat类指定给ObjectMapper.setDateFormat方法,则日期是正确的。

除了这不会将毫秒置于我想要的格式中,所以我对ISO8601DateFormat类进行了子类化并覆盖了该format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) 方法。

/**
 * Provides a ISO8601 date format implementation that includes milliseconds
 *
 */
public class ISO8601DateFormatWithMillis extends ISO8601DateFormat {

  /**
   * For serialization
   */
  private static final long serialVersionUID = 2672976499021731672L;


  @Override
  public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition)
  {
      String value = ISO8601Utils.format(date, true);
      toAppendTo.append(value);
      return toAppendTo;
  }
}
Run Code Online (Sandbox Code Playgroud)


jjm*_*tes 1

您的日期对象可能没问题,因为您发送了使用 GMT 时区的 ISO 格式编码的日期,并且当您打印日期时您处于美国东部时间。

请注意,Date 对象在打印时执行时区转换。您可以date通过以下方式检查您的对象是否正确:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.setTime(date);
System.out.println (cal);
Run Code Online (Sandbox Code Playgroud)