Duration.ofDays 会生成 UnsupportedTemporalTypeException 异常。

28

我正在尝试学习新的日期和时间 API。我的代码除了最后一行以外都在工作:

LocalDate current=LocalDate.now();
System.out.println(current);

LocalDate personaldate=LocalDate.of(2011,Month.AUGUST, 15);
System.out.println(personaldate);

LocalDate afterten=current.plus(Period.ofDays(10));
System.out.println(afterten);

// error occurs here        
System.out.println(afterten.plus(Duration.ofDays(3)));

当我尝试添加一段持续时间(以天为单位)时,它会产生一个错误。有人能帮我理解为什么吗?

错误:

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds                                                                                             
        at java.time.LocalDate.plus(LocalDate.java:1241)                                                                                                                                              
        at java.time.LocalDate.plus(LocalDate.java:137)                                                                                                                                               
        at java.time.Duration.addTo(Duration.java:1070)                                                                                                                                               
        at java.time.LocalDate.plus(LocalDate.java:1143)                                                                                                                                              
        at TestClass.main(TestClass.java:15)    
5个回答

54

尽管被接受的答案完全正确,但当我遇到这个问题时,我正在寻找一个简单的解决方案。

我发现使用Period无法计算我的两个LocalDate对象之间的天数。(告诉我两者之间有多少年、月和日,是的,但不能只是天数。)

然而,为了得到我想要的结果,只需将每个对象添加"atStartOfDay"方法即可。

因此,我的错误代码:

long daysUntilExpiry = Duration.between(LocalDate.now(), training.getExpiryDate()).toDays();

仅仅被调整为:

long daysUntilExpiry = Duration.between(LocalDate.now().atStartOfDay(), training.getExpiryDate().atStartOfDay()).toDays();

这样做可以将对象转换为LocalDateTime对象,可与Duration一起使用。由于两个对象的“时间”部分都是一天的开始,因此没有区别。

希望这能帮助其他人。


你是什么意思说“使用Period无法计算天数”?Period.between(date1, date2).days可以实现这个功能。 - Demigod
3
“@Demigod不确定我是否在规范中看到过Period的公共可访问属性 - 也许您使用的是与我不同的Java版本? .getDays()将获取期间中的天数,如果首先删除所有月份和年份,则非常适用于“距离我的大假还有2年7个月和23天”的逻辑,但对于我尝试做的事情则无用。” - wombling - Chris Paine
wombling - Chris Paine,你说得完全正确!我实际上认为Period.getDays返回完整的天数。我错了。谢谢! - Demigod

28

Duration试图向LocalDate添加纳秒,这是不正确的。但Period添加天数。这涉及到Period和Duration类的实现。 - Azat Nugusbayev
4
把英语翻译成中文。只返回已翻译的文本。编辑您的答案并详细说明。 - Sotirios Delimanolis
我想补充一下:你确实可以将天数的持续时间应用于 LocalDateTime 对象——它会增加日期的日组件,因为它会将 24 小时内的秒数(乘以传递给该方法的天数)添加到时间中——这就是为什么在 LocalDate 上失败的原因,因为 LocalDate 没有“秒”组件。 - Zippy

12
//(year,month,day)

LocalDate beginDate = LocalDate.of(1899,12,31);    
LocalDate today = LocalDate.now();    
ChronoUnit.DAYS.between(beginDate, today)

虽然这段代码片段可能是解决方案,但包括解释真的有助于提高您的帖子质量。请记住,您正在回答未来读者的问题,而这些人可能不知道您的代码建议原因。 - Narendra Jadhav
5
Period#getDays 方法的问题在于它只返回时间差中的“天”部分,所以如果时间差是3个月2天,它只返回2。而 ChronoUnit 可以返回3个月2天总共相当于多少天的准确数字。 - Gwaptiva

3

正如之前所示,Duration始终是基于秒的,而Period以天为概念。 当试图在以日期为基础的LocalDate上添加秒时,代码会抛出异常。

像这样更改您的代码可以展示差异:当涉及到每天内的瞬间时,请使用LocalDateTime:

LocalDateTime current = LocalDateTime.now();
System.out.println(current);

LocalDateTime afterten = current.plus(Period.ofDays(10));
System.out.println(afterten);

// error occurred here - but with LocalDateTime is resolved!
System.out.println(afterten.plus(Duration.ofDays(3)));

1

尝试在单元测试中运行以下代码,亲自验证您的问题的接受答案应该是Ravi所述的ChronoUnit.DAYS.between()

LocalDate date1 = LocalDate.of(2020,6,2);
LocalDate date2 = LocalDate.of(2020,7,4);
System.out.printf("ChronoUnit.DAYS = %d%n", ChronoUnit.DAYS.between(date1, date2));
System.out.printf("Period.between = %d%n",Period.between(date1, date2).getDays());

由于输出将如下所示:
ChronoUnit.DAYS = 32
Period.between = 2

周期函数会错误地仅返回差异的天数部分(忽略月份和年份等更高阶差异)。
System.out.printf("Duration.between = %d%n",Duration.between(date1, date2).getSeconds());

由于 LocalDate 没有提供足够的信息进行秒级计算(未定义小时,分钟和秒),因此这将抛出异常。 因此,您需要通过调用 date1.atStartOfDay() 将其转换为 LocalDateTime。
System.out.printf("Duration.between = %d%n",Duration.between(date1.atStartOfDay(), date2.atStartOfDay()).get(ChronoUnit.DAYS));

这个调用会抛出java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Days异常,因为在Java中Duration类的get方法的实现方式导致了这种情况。
@Override
public long get(TemporalUnit unit) {
    if (unit == SECONDS) {
        return seconds;
    } else if (unit == NANOS) {
        return nanos;
    } else {
        throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接