Java 8 中日期反序列化的 Jackson 仍然会发生 2038 年问题

Year 2038 issue still happens with Jackson of date deserialization in Java 8

简单地说,我有以下 class 来让我的 JSON 从远程响应接收到的正文反序列化为 CreditCardDTOexp_date 中收到的日期,例如“0820”对于 8/2010,“0240”对于 2/2040:

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Date;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonPropertyOrder(alphabetic = true)
public class CreditCardDTO {
    private String brand;
    private Date expirationDate;

    @JsonProperty("brand")
    public String getBrand() {
        return brand;
    }

    @JsonProperty("credit_card_type")
    public CreditCardDTO setBrand(String brand) {
        this.brand = brand;
        return this;
    }

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
    @JsonProperty("expirationDate")
    public Date getExpirationDate() {
        return expirationDate;
    }

    @JsonFormat(pattern = "MMyy")
    @JsonProperty("exp_date")
    public CreditCardDTO setExpirationDate(Date expirationDate) {
        System.out.println(expirationDate);
        this.expirationDate = expirationDate;
        return this;
    }
}

问题是2038年以前的都可以,但是一旦数据到了关键日期之后,还是会出现,数据回到1941年,我搜索了一下,发现应该不是发生在 Java 8 : Why should a Java programmer care about year 2038 bug? ,所以我想知道这里有什么问题!

Jackson 版本 2.8.0,Java8 是肯定的。

虽然我不了解 Jackson,但我可以告诉你,你处理信用卡到期数据的方法很糟糕。

首先,您选择自己动手而不是参考现有的 classes 和标准。始终搜索以前的工作;自己动手做应该是最后的手段,而不是第一个。少一些狂野的牛仔,多一些根据先例进行判断。

其次,您使用的是遗留的麻烦的旧日期时间 classes,现在已被 java.time classes 取代。

YearMonth

要表示年和月,请使用 Java 中内置的 YearMonth class。与传统 classes.

不同,月份的编号非常合理,1 月至 12 月为 1-12
YearMonth ym = YearMonth.of( 2040 , 3 ) ; 

顺便说一句,您可能会在工作中发现 Month 枚举。

YearMonth ym = YearMonth.of( 2040 , Month.MARCH ) ; 

使用此 YearMonth class 作为您的会员而不是特定日期。

与今天等日期进行比较时,获取该日期的 YearMonth

ZoneId z = ZoneId.of( "Asia/Amman" ) ;
LocalDate today = LocalDate.now( z ) ;
YearMonth ymToday = YearMonth.from( today ) ;

Boolean isExpired = ymToday.isAfter( ym ) ;

ISO 8601

ISO 8601 标准定义了许多实用的合理格式,用于将日期时间值表示为文本。

年-月的标准格式是YYYY-MM。所以 2040 年 3 月是 2040-03.

java.time classes 在解析或生成字符串时默认使用标准格式。

生成字符串。

ym.toString()  

2040-03

解析字符串。

YearMonth ym = YearMonth.parse( "2040-03" );

始终使用 4 位数年份

对于存储和表示,年份始终使用四位数字。无穷无尽的混乱、错误和歧义不值得在纸上节省两个八位字节的memory/storage或半厘米的space。