Java 8 中日期反序列化的 Jackson 仍然会发生 2038 年问题
Year 2038 issue still happens with Jackson of date deserialization in Java 8
简单地说,我有以下 class 来让我的 JSON 从远程响应接收到的正文反序列化为 CreditCardDTO
在 exp_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。
简单地说,我有以下 class 来让我的 JSON 从远程响应接收到的正文反序列化为 CreditCardDTO
在 exp_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.
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。