设置杰克逊时区以进行日期反序列化

发布于 2024-12-06 16:53:55 字数 1085 浏览 1 评论 0原文

我正在使用 Jackson(通过 Spring MVC Annotations)将字段从 JSON 反序列化为 java.util.Date 。 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

});

JSON消息:

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

Spring 控制器:

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

I'm using Jackson (via Spring MVC Annotations) to deserialize a field into a java.util.Date from JSON. The POST looks like - {"enrollDate":"2011-09-28T00:00:00.000Z"}, but when the Object is created by Spring & Jackson it sets the date as "2011-09-27 20:00:00".

How can I set the proper timezone in Jackson?
Or if that is not the problem, how do I send EST from the JSON message?

Javascript/jQuery:

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


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

});

JSON Message:

{"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
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

街角迷惘 2024-12-13 16:53:55

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

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

如果这种方式不起作用,请尝试用单引号将 Z 括起来,即 pattern="yyyy-MM-dd'T'HH:mm:ss.SSS' Z'"

In Jackson 2+, you can also use the @JsonFormat annotation:

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

If it doesn't work this way then try wrapping Z with single quotes, i.e. pattern="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"

梅窗月明清似水 2024-12-13 16:53:55

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

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

Have you tried this in your application.properties?

spring.jackson.time-zone= # Time zone used when formatting dates. For instance `America/Los_Angeles`
救星 2024-12-13 16:53:55

如果您确实希望杰克逊返回具有 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

它对那些了解时区的人-p

If you really want Jackson to return a date with another time zone than UTC (and I myself have several good arguments for that, especially when some clients just don't get the timezone part) then I usually do:

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

It has no adverse effects on those that understand the timezone-p

蓬勃野心 2024-12-13 16:53:55

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

如何在 Jackson 版本 2.11.0 中正确设置时区到 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);
  }
`

Looks like older answers were fine for older Jackson versions, but since objectMapper has method setTimeZone(tz), setting time zone on a dateFormat is totally ignored.

How to properly setup timeZone to the ObjectMapper in Jackson version 2.11.0:

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

Full example

  @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);
  }
`
江南月 2024-12-13 16:53:55

我正在使用 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”,而是“2014-02-13T08:09:09.859” JSON 消息中的 +0000” 显然是不正确的。我没有时间逐步浏览 Jackson 库源代码来找出发生这种情况的原因,但是我发现如果我只是将 Jackson 提供的 ISO8601DateFormat 类指定给 ObjectMapper.setDateFormat< /code> 方法日期正确。

除此之外,这不会将毫秒置于我想要的格式中,因此我对 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;
  }
}

I am using Jackson 1.9.7 and I found that doing the following does not solve my serialization/deserialization timezone issue:

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

Instead of "2014-02-13T20:09:09.859Z" I get "2014-02-13T08:09:09.859+0000" in the JSON message which is obviously incorrect. I don't have time to step through the Jackson library source code to figure out why this occurs, however I found that if I just specify the Jackson provided ISO8601DateFormat class to the ObjectMapper.setDateFormat method the date is correct.

Except this doesn't put the milliseconds in the format which is what I want so I sub-classed the ISO8601DateFormat class and overrode the format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition)
method.

/**
 * 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;
  }
}
我纯我任性 2024-12-13 16:53:55

刚刚遇到这个问题,终于意识到 LocalDateTime 没有任何时区信息。如果您收到带有时区信息的日期字符串,则需要使用它作为类型:

ZonedDateTime

检查此链接

Just came into this issue and finally realised that LocalDateTime doesn't have any timezone information. If you received a date string with timezone information, you need to use this as the type:

ZonedDateTime

Check this link

酒废 2024-12-13 16:53:55

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

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

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

Your date object is probably ok, since you sent your date encoded in ISO format with GMT timezone and you are in EST when you print your date.

Note that Date objects perform timezone translation at the moment they are printed. You can check if your date object is correct with:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.setTime(date);
System.out.println (cal);
卖梦商人 2024-12-13 16:53:55

我在日历反序列化方面遇到了同样的问题,解决了扩展 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;

I had same problem with Calendar deserialization, solved extending CalendarDeserializer.
It forces UTC Timezone
I paste the code if someone need it:

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

in JSON model class just annotate the field with:

@JsonDeserialize(using = UtcCalendarDeserializer.class)
private Calendar myCalendar;
蔚蓝源自深海 2024-12-13 16:53:55

对于现在(2020 年 2 月)遇到这个问题的任何人来说,以下 Medium 帖子对于我们克服这个问题至关重要。

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()
        ));
    }
}

For anyone struggling with this problem in the now (Feb 2020), the following Medium post was crucial to overcoming it for us.

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

In our case, the app uses @EnableWebMvc and would break if removed so, the section on 'The Life without Spring Boot' was critical. Here's what ended up solving this for us. It allows us to still consume and produce JSON and XML as well as format our datetime during serialization to suit the app's needs.

@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()
        ));
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文