使用Instant.parse解析超大AD日期报错,BC日期却正常?
为什么Instant.parse解析超大AD日期报错,但BC日期却正常?
尝试使用Instant.parse方法解析一个远小于Instant.MAX的超大公元后(AD)日期时遇到了解析错误,但格式类似的公元前(BC)日期却能正常解析。
代码示例
String input = "78000000-01-01T00:00:00Z"; Instant instant = Instant.parse(input);
抛出异常
Exception in thread "main" java.time.format.DateTimeParseException: Text '78000000-01-01T00:00:00Z' could not be parsed at index 0 at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2106) at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:2008) at java.base/java.time.Instant.parse(Instant.java:399)
而执行以下代码却能正常运行:
String input = "-78000000-01-01T00:00:00Z"; Instant instant = Instant.parse(input);
这是不是Java的Bug?
结论:这不是Java Bug,是默认格式的年份位数限制导致的
Instant.parse默认使用DateTimeFormatter.ISO_INSTANT格式器,该格式器对公元后(AD)年份的解析有最多4位数字的限制,而公元前(BC)年份(带负号)的解析逻辑允许更长的数字长度,因此会出现两种情况的差异。
Instant.MAX对应的年份是+1000000000(10位数字),但默认格式器并未放开AD年份的位数限制,导致8位的AD年份无法被解析。
解决方案:自定义DateTimeFormatter支持长位数AD年份
如果需要解析超过4位的公元后年份,可以自定义格式器,明确指定年份的最大位数:
import java.time.Instant; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.ChronoField; import java.time.format.SignStyle; public class Main { public static void main(String[] args) { DateTimeFormatter formatter = new DateTimeFormatterBuilder() // 允许年份为4到10位,公元后不带负号 .appendValue(ChronoField.YEAR, 4, 10, SignStyle.EXCEEDS_PAD) .appendPattern("-MM-dd'T'HH:mm:ssX") .toFormatter() .withZone(ZoneOffset.UTC); String input = "78000000-01-01T00:00:00Z"; Instant instant = formatter.parse(input, Instant::from); System.out.println(instant); // 输出:78000000-01-01T00:00:00Z } }
该自定义格式器通过SignStyle.EXCEEDS_PAD允许公元后年份使用超过4位的数字,同时指定最大10位(匹配Instant.MAX的年份位数),从而支持解析超大AD日期。
内容的提问来源于stack exchange,提问作者Sogawa-sps
相关产品推荐
相关产品推荐

