如何从模式创建Java时间瞬间?

如何从模式创建Java时间瞬间?,java,java-time,Java,Java Time,考虑一个代码: TemporalAccessor date = DateTimeFormatter.ofPattern("yyyy-MM-dd").parse("9999-12-31"); Instant.from(date); 最后一行引发异常: Unable to obtain Instant from TemporalAccessor: {},ISO resolved to 9999-12-31 of type java.time.format.Parsed 如何从yyyy-MM-dd

考虑一个代码:

TemporalAccessor date = DateTimeFormatter.ofPattern("yyyy-MM-dd").parse("9999-12-31");
Instant.from(date);
最后一行引发异常:

Unable to obtain Instant from TemporalAccessor: {},ISO resolved to 9999-12-31 of type java.time.format.Parsed
如何从
yyyy-MM-dd
模式创建
Instant

public static void main(String[] args) throws ParseException {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd").parse("2016-12-31").toInstant());
}
上述代码给出以下输出:

2016-12-31T00:00:00Z


我已经使用Java8的特性(“toInstant”方法)回答了这个问题。希望这能回答您的问题……

问题不在于您使用的是9999年。
Instant.MAX
字段的计算结果是时间戳
1000000000-12-31T23:59:59.9999999z
,因此9999作为一年是可以的

处理
temporalaccessor
而不是语义更丰富的类型,如
LocalDateTime
ZonedDateTime
,就像使用
Map
对对象及其属性建模,而不是编写
——您必须确保值具有字段(如秒、纳秒等)这是接收到它的对象所期望的,而不是依赖于更高级别类中正式声明的操作来防止依赖关系得不到满足

在您的例子中,时态访问器可能包含给定的解析日期字段,但没有
Instant
所需的“seconds”字段。在大多数情况下,最好使用语义更丰富的类型,如
LocalDateTime

因为您只有日期字段,所以应该将其解析为日期,然后在将其转换为瞬间之前添加时间字段。以下是一种使用LocalDate解析日期的方法:

LocalDate localDate = LocalDate.parse("2016-04-17");
LocalDateTime localDateTime = localDate.atStartOfDay();
Instant instant = localDateTime.toInstant(ZoneOffset.UTC);

或者您只对日期本身感兴趣(9999年12月31日),在这种情况下,合适的类型应该是
LocalDate

LocalDate date = LocalDate.parse("9999-12-31");
或者您确实需要一个
即时
,在这种情况下,您需要设置一个时区,例如,东京的
00:00

Instant instant = date.atStartOfDay(ZoneId.of("Asia/Tokyo")).toInstant();
字符串“9999-12-31”仅包含有关日期的信息。它不包含关于一天中的时间或偏移量的任何信息。因此,没有足够的信息来创建
即时
。(其他日期和时间库更为宽松,但
java.time
避免默认这些值)

您的第一个选择是使用
LocalDate
而不是“即时:

LocalDate date = LocalDate.parse("9999-12-31");
您的第二个选择是对日期进行后期处理以将其转换为瞬间,这需要一个时区,此处选择巴黎:

LocalDate date = LocalDate.parse("9999-12-31");
Instant instant = date.atStartOfDay(ZoneId.of("Europe/Paris")).toInstant();
第三种选择是将时区添加到格式化程序中,并默认为一天中的时间:

static final DateTimeFormatter FMT = new DateTimeFormatterBuilder()
    .appendPattern("yyyy-MM-dd")
    .parseDefaulting(ChronoField.NANO_OF_DAY, 0)
    .toFormatter()
    .withZone(ZoneId.of("Europe/Paris"));
Instant instant = FMT.parse("9999-31-12", Instant::from);
(如果这不起作用,请确保您拥有最新的JDK 8版本,因为此区域中的错误已修复)


值得注意的是,这些可能性中没有一种直接使用
TemporalAccessor
,因为这种类型是一种低级框架接口,大多数应用程序开发人员无法使用;D例如,在2016年试一下。使用LocalDate.parse(),通过选择一个时间(atStartOfDay?)将其转换为LocalDateTime,通过选择一个时区将其转换为ZonedDateTime(日期在法国代表一个瞬间吗?在英国代表一个瞬间吗?在日本代表一个瞬间吗?),然后将ZonedDateTime转换为一个瞬间。瞬间就是瞬间。9999年12月31日是一个日期,但不是一个瞬间。因此,如果只需要一个日期,您可以将其解析为LocalDate,或者您必须指定缺少的位(一个时间+一个区域偏移量或时区)。该代码任意设置了很多内容(并将旧的日期API与新的Java时间API混合)…@assylias yes'toInstant()'方法仅在最新版本的java中可用。我会在回答中提到,你能解释一下吗。我可以知道投票被否决的原因吗。这将有助于我改进我的答案。我认为否决票的原因是我上面所说的:(I)您不必要地混合了API,这令人困惑;(ii)您的示例的输出取决于用户时区(例如,如果您在夏威夷,它将打印
2016-12-31T10:00:00Z
)。与您所展示的相反,
java.util.Instant
方法不使用
DateTimeFormatter
。相反,您必须执行
FMT.parse(“9999-31-12”,Instant::from)
。作为作者,您能否解释一下为什么
Instant
在这方面不同于其他类,例如
LocalDateTime
?最初,
Instant
根本不适用于
DateTimeFormatter
。这在开发过程中已更改,但未添加您引用的方法。这就是说,因为许多格式化程序不使用即时
方法,所以有一种情况可以说,添加这样的方法会添加一些经常失败的东西,并会让用户感到烦恼。谢谢!这个答案帮助我用Java代码解析ISO 8601时间戳,没有分钟字段,即“2019-06-11T08:00Z”:
Instant.from((新DateTimeFormatterBuilder().appendPattern(“yyyy-MM-dd'T'HH':'MM'Z”)。解析默认值(ChronoField.SECOND\u OF_MINUTE,0)。解析默认值(ChronoField.NANO\u OF_OF_SECOND,0)。toFormatter().withZone(ZoneId.OF(“UTC”)).parse(字符串))