为日期反序列化设置jackson时区

vltsax25  于 2021-07-03  发布在  Java
关注(0)|答案(9)|浏览(353)

我正在使用jackson(通过springmvc注解)将字段反序列化为 java.util.Date 来自json。帖子看起来像- {"enrollDate":"2011-09-28T00:00:00.000Z"} ,但当对象由spring&jackson创建时,它将日期设置为 "2011-09-27 20:00:00" .
如何在jackson中设置正确的时区?或者如果这不是问题所在,如何从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
}
eblbsuwk

eblbsuwk1#

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

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

在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;
  }
}
8ehkhllq

8ehkhllq2#

看起来老版的答案对老版的Jackson来说还不错,但自从 objectMapper has方法 setTimeZone(tz) ,将完全忽略在日期格式上设置时区。
如何在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);
  }
`
iqxoj9l9

iqxoj9l93#

如果你真的想让jackson返回一个非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的人没有不利影响

pkwftd7m

pkwftd7m4#

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

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

doinxwow5#

对于任何在现在(2020年2月)与这个问题作斗争的人来说,下面的中篇文章对我们克服这个问题至关重要。
https://medium.com/@ttulka/spring-http-message-converters-customizing-770814eb2b55
在我们的例子中,这个应用程序使用@enablewebmvc,如果删除它就会崩溃,那么“没有spring boot的生活”一节是至关重要的。这就是最终为我们解决这个问题的原因。它允许我们继续使用和生成json和xml,并在序列化过程中格式化datetime以满足应用程序的需要。

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

fhg3lkii6#

刚开始讨论这个问题,终于意识到localdatetime没有任何时区信息。如果收到包含时区信息的日期字符串,则需要将其用作类型:
分区日期
检查此链接

pvabu6sv

pvabu6sv7#

在jackson 2+中,还可以使用@jsonformat注解:

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

u1ehiz5o8#

我有同样的问题日历反序列化,解决了扩展日历反序列化。
它强制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;
zvms9eto

zvms9eto9#

您的日期对象可能还可以,因为您发送的日期是用gmt时区的iso格式编码的,并且打印日期时您处于est。
请注意,日期对象在打印时执行时区转换。你可以检查一下 date 对象正确:

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

相关问题