Duration.ofDays generates UnsupportedTemporalTypeException
Asked Answered
R

5

28

I am trying to learn the new Date & Time API. My code is working except for the last line:

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)));

When I try and add a Duration in days, it generates an error. Can anyone help me understand why?

Error:

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)    
Ramiah answered 23/12, 2015 at 17:31 Comment(0)
K
29

A Duration measures an amount of time using time-based values (seconds, nanoseconds). A Period uses date-based values (years, months, days). here is the link

https://docs.oracle.com/javase/tutorial/datetime/iso/period.html

the same as in JodaTime

Kenlay answered 23/12, 2015 at 17:42 Comment(3)
Duration tries to add nanoseconds, to a LocalDate, which is not correct. But period adds days. It is about implementaion of Period and Duraion classes.Kenlay
Edit your answer and add that, in detail.Octonary
Would like to add that you can apply a duration of days to a LocalDateTime object - it will increment the day component of the date, and works because it adds the number of seconds in 24 hours (multiplied by the number of days you pass in to the method) to the time - this is why it fails on LocalDate because LocalDate has no 'seconds' component.Farthest
H
55

Whilst the accepted answer is completely correct, when I arrived at this question, I was looking for a simple solution to my problem.

I found using Period would not allow me to count the number of days between my two LocalDate objects. (Tell me how many years, months and days between the two, yes, but not just then number of days.)

However, to get the result I was after was as simple as adding the LocalDate method "atStartOfDay" to each of my objects.

So my erronious code:

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

was simply adjusted to:

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

Doing this make the objects into LocalDateTime objects which can be used with Duration. Because both object have start of day as the "time" part, there is no difference.

Hope this helps someone else.

Hathor answered 11/2, 2018 at 14:0 Comment(3)
What do you mean "I found using Period would not allow me to count the number of days"? Period.between(date1, date2).days actually does this.Laith
@Laith not sure I've seen a publicly accessible attribute of Period in the spec - perhaps you are using a different version of Java than I was? .getDays() would get the number of days in period if one first removed all the months and years. So very useful for the "2 years, 7 months and 23 days until my big holiday" type logic, but not for what I was trying to do.Hathor
wombling - Chris Paine, you're completely right! I actually was thinking that the Period.getDays returns full number of days. I was wrong. Thanks!Laith
K
29

A Duration measures an amount of time using time-based values (seconds, nanoseconds). A Period uses date-based values (years, months, days). here is the link

https://docs.oracle.com/javase/tutorial/datetime/iso/period.html

the same as in JodaTime

Kenlay answered 23/12, 2015 at 17:42 Comment(3)
Duration tries to add nanoseconds, to a LocalDate, which is not correct. But period adds days. It is about implementaion of Period and Duraion classes.Kenlay
Edit your answer and add that, in detail.Octonary
Would like to add that you can apply a duration of days to a LocalDateTime object - it will increment the day component of the date, and works because it adds the number of seconds in 24 hours (multiplied by the number of days you pass in to the method) to the time - this is why it fails on LocalDate because LocalDate has no 'seconds' component.Farthest
F
12
//(year,month,day)

LocalDate beginDate = LocalDate.of(1899,12,31);    
LocalDate today = LocalDate.now();    
ChronoUnit.DAYS.between(beginDate, today)
Forsythe answered 8/7, 2018 at 13:18 Comment(2)
While this code snippet may be the solution, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.Loudermilk
The problem with Period#getDays is that it only returns the "day" part of the difference, so if the difference is 3 months and 2 days, it returns 2. The ChronoUnit returns the actual total number of days that 3 months and 2 days add up to.Cherey
T
3

As hinted before, Duration is always seconds-based whereas Period honours the day as concept. The code throws an exception when it tries to add seconds on a LocalDate - which is also day-based.

Changing your code like this shows the difference: use LocalDateTime when getting down to instants within days:

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)));
Tattle answered 29/5, 2018 at 7:2 Comment(0)
L
1

Try to run following code in a Unit test and see for yourself that the accepted answer to your problem should be ChronoUnit.DAYS.between() as stated by Ravi.

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());

Because the output will look as follows:

ChronoUnit.DAYS = 32
Period.between = 2

Period will incorrectly return only the days portion of the difference (ignoring higher order differences like months and years).

System.out.printf("Duration.between = %d%n",Duration.between(date1, date2).getSeconds());

This will throw an exception as LocalDate does not provide enough information for seconds calculations (undefined hour, minutes and seconds). Therefore you would have to convert it to LocalDateTime for example by calling date1.atStartOfDay().

System.out.printf("Duration.between = %d%n",Duration.between(date1.atStartOfDay(), date2.atStartOfDay()).get(ChronoUnit.DAYS));

This call will simply throw java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Days because of how the get method on Duration class is implemented in Java:

@Override
public long get(TemporalUnit unit) {
    if (unit == SECONDS) {
        return seconds;
    } else if (unit == NANOS) {
        return nanos;
    } else {
        throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
    }
}
Ladanum answered 28/1, 2021 at 13:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.