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

时间:2011-09-26 14:42:05

标签: json spring-mvc jackson

我正在使用Jackson(通过Spring MVC Annotations)将字段从JSON反序列化为java.util.Date。 POST看起来像 - {"enrollDate":"2011-09-28T00:00:00.000Z"},但当对象由Spring&创建时杰克逊将日期设为"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

});

JSON消息:

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

Spring Controller:

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

9 个答案:

答案 0 :(得分:38)

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

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

答案 1 :(得分: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

对那些了解timezone-p

的人没有任何负面影响

答案 2 :(得分:5)

您是否在application.properties中尝试过这个?

spring.jackson.time-zone= # Time zone used when formatting dates. For instance `America/Los_Angeles`

答案 3 :(得分:4)

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

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

而不是“2014-02-13T20:09:09.859Z”我在JSON消息中得到“2014-02-13T08:09:09.859 + 0000”,这显然是不正确的。我没有时间单步执行杰克逊库源代码来弄清楚为什么会发生这种情况,但我发现如果我只是指定杰克逊为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;
  }
}

答案 4 :(得分:1)

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

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

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.setTime(date);
System.out.println (cal);

答案 5 :(得分:1)

我遇到了与日历反序列化相同的问题,解决了扩展CalendarDeserializer的问题。
它迫使UTC时区
如果有人需要,我会粘贴代码:

@JacksonStdImpl
public class UtcCalendarDeserializer extends CalendarDeserializer {

    TimeZone TZ_UTC = TimeZone.getTimeZone("UTC");

    @Override
    public Calendar deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonToken t = jp.getCurrentToken();
        if (t == JsonToken.VALUE_NUMBER_INT) {
            Calendar cal = Calendar.getInstance(TZ_UTC);
            cal.clear();
            cal.setTimeInMillis(jp.getLongValue());

            return cal;
        }

        return super.deserialize(jp, ctxt);
    }
}

在JSON模型类中,只需使用:

注释该字段
@JsonDeserialize(using = UtcCalendarDeserializer.class)
private Calendar myCalendar;

答案 6 :(得分:0)

刚刚进入这个问题并最终意识到 LocalDateTime 没有任何时区信息。如果您收到带有时区信息的日期字符串,则需要将其用作类型:

<强> ZonedDateTime

选中此link

答案 7 :(得分:0)

对于现在(2020年2月)在这个问题上挣扎的任何人,以下中级帖子对于我们克服这一问题至关重要。

https://medium.com/@ttulka/spring-http-message-converters-customizing-770814eb2b55

在我们的例子中,该应用程序使用@EnableWebMvc,如果删除该应用程序则会损坏,因此“无Spring Boot的生活”这一节至关重要。这就是最终为我们解决此问题的方法。它使我们仍然可以使用和产生JSON和XML,以及在序列化期间格式化日期时间以适应应用程序的需求。

@Configuration
@ComponentScan("com.company.branch")
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(0, new MappingJackson2XmlHttpMessageConverter(
                new Jackson2ObjectMapperBuilder()
                        .defaultUseWrapper(false)
                        .createXmlMapper(true)
                        .simpleDateFormat("yyyy-mm-dd'T'HH:mm:ss'Z'")
                        .build()
        ));
    converters.add(1, new MappingJackson2HttpMessageConverter(
                new Jackson2ObjectMapperBuilder()
                        .build()
        ));
    }
}

答案 8 :(得分:0)

对于较旧的Jackson版本,看起来较旧的答案似乎很好,但是由于objectMapper具有方法setTimeZone(tz),因此完全忽略了对dateFormat设置时区。

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

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setTimeZone(TimeZone.getTimeZone("Europe/Warsaw"));

完整示例

  @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);
  }
`