有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

带Spring boot和Jackson的java日期时区

我正在开发一个处理日期的spring boot应用程序。当我提交具有startDateTimeendDateTime(均为java.util.Date类型)的约会对象时,我发送如下格式:

{
    "lastName": "Jhon",
    "firstName": "Doe",
    "email": "jhon.doe@gmail.com",
    "description": "MyDescription",
    "startDateTime": "2017-10-09T22:43:07.109+0300",
    "endDateTime": "2017-10-09T21:40:07.109+0300",
}

当数据保存在数据库中时,它的时区是正确的,当我尝试检索回数据时,当我调试时,它们似乎是正确的。但是,一旦Jackson序列化了这些数据,我就有一个输出,其值如下:

"startDateTime": "2017-10-09T19:43:07.109+0000",
"endDateTime": "2017-10-09T18:40:07.109+0000",

我如何配置Jackson以使用存储库中数据随附的时区

----更新---------

我用OffsetDateTime尝试了答案,但输出非常奇怪:

"startDateTime": {
        "offset": {
            "totalSeconds": 7200,
            "id": "+02:00",
            "rules": {
                "fixedOffset": true,
                "transitionRules": [],
                "transitions": []
            }
        },
        "month": "OCTOBER",
        "year": 2017,
        "hour": 21,
        "minute": 49,
        "nano": 654000000,
        "second": 15,
        "dayOfMonth": 9,
        "dayOfWeek": "MONDAY",
        "dayOfYear": 282,
        "monthValue": 10
    }

我想要一些类似于:

2017-10-09T22:43:07.109+0300


共 (2) 个答案

  1. # 1 楼答案

    A java.util.Date{a1}。一旦将String反序列化为Date,偏移量+0300就会丢失:日期只保留时间戳值,它无法知道它来自哪个原始时区

    如果输出必须始终处于+03:00偏移量,可以使用com.fasterxml.jackson.annotation.JsonFormat注释在相应字段中直接设置:

    @JsonFormat(timezone = "GMT+03:00")
    private Date startDateTime;
    
    @JsonFormat(timezone = "GMT+03:00")
    private Date endDateTime;
    

    这样,日期字段将始终序列化为+03:00偏移量:

    {
      "startDateTime":"2017-10-09T22:43:07.109+0300",
      "endDateTime":"2017-10-09T21:40:07.109+0300"
    }
    

    如果输入可以位于任何其他偏移量中(不仅是+03:00),并且您希望保留它,java.util.Date不是理想的类型。如果您使用的是Java>;=八,

    对于Java 6和Java 7,有ThreeTen Backport和相应的Jackson module——虽然我还没有测试过,但代码可能类似,因为Three Ten Backport包含相同的类和方法,只是包不同(在Java 8中是^{,在Three Ten Backport中是^{

    为了保留日期、时间和偏移量,最好的替代方法是OffsetDateTime类。因此,您只需更改字段类型并设置相应的格式:

    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXX")
    private OffsetDateTime startDateTime;
    
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXX")
    private OffsetDateTime endDateTime;
    

    在对象映射器中,还必须注册JavaTimeModule并禁用^{} feature,以便保留偏移量(默认行为是转换为Jackson上下文的时区,该时区可能与输入中使用的时区不同——通过禁用此选项,偏移量将被保留)

    您可以使用JacksonConfigurator(作为explained in this answer)并执行以下配置:

    ObjectMapper om = new ObjectMapper();
    om.registerModule(new JavaTimeModule());
    om.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
    

    这种配置通常就足够了,但您也可以将SerializationFeature.WRITE_DATES_AS_TIMESTAMPS设置为false,以防万一


    如果仍然需要使用java.util.Date,可以使用API从它转换/转换到它。在Java 8中,有一个新的Date.from方法:

    // convert to java.util.Date
    public Date getStartAsJavaUtilDate() {
        return Date.from(startDateTime.toInstant());
    }
    

    在Thine Ten Backport中,有org.threeten.bp.DateTimeUtils类:

    // convert to java.util.Date
    DateTimeUtils.toDate(startDateTime.toInstant());
    

    不过,要将Date转换回OffsetDateTime,需要更加复杂。Date对象没有时区信息,因此无法知道原始偏移量。另一种方法是将原始偏移量保留在单独的变量中:

    // keep the original offset
    ZoneOffset startDateOffset = startDateTime.getOffset();
    

    然后,可以将Date转换为Instant,然后将其转换为原始偏移量:

    // convert java.util.Date to original offset (Java 8)
    startDateTime = date.toInstant().atOffset(startDateOffset);
    
    // ThreeTen Backport
    startDateTime = DateTimeUtils.toInstant(date).atOffset(startDateOffset);
    
  2. # 2 楼答案

    如果你在spring boot中使用swagger,并且你的约会总是被连续化。
和序列化功能。将日期写为时间戳&;春天杰克逊。序列化。将日期写入时间戳=false 解决方案对我不起作用。将其添加到带有@SpringBootApplication注释的类中:

    问题:序列化功能。WRITE_DATES_AS_TIMESTAMPS值不是从spring配置文件中读取的,需要按顺序设置为false
在序列化时隐藏长值

    @Autowired
    private RequestMappingHandlerAdapter handlerAdapter;
    
    @EventListener
    public void handleContextRefresh(ContextRefreshedEvent event) {
        handlerAdapter
                .getMessageConverters()
                .stream()
                .forEach(c -> {
                    if (c instanceof MappingJackson2HttpMessageConverter) {
                        MappingJackson2HttpMessageConverter jsonMessageConverter = (MappingJackson2HttpMessageConverter) c;
                        ObjectMapper objectMapper = jsonMessageConverter.getObjectMapper();
                        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
                    }
                });
    }