Java.time.Instant.plus (long amountToAdd, TemporalUnit unit) Unsupported block

I am trying to add a few years to the current time. My code looks like this:

// ten yeas ago int backYears = 10; Instant instant = ChronoUnit.YEARS.addTo(Instant.now(), -backYears); 

But I got an exception:

 java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Years at java.time.Instant.plus(Instant.java:862) 

When I opened the Instant.plus method, I see the following:

 @Override public Instant plus(long amountToAdd, TemporalUnit unit) { if (unit instanceof ChronoUnit) { switch ((ChronoUnit) unit) { case NANOS: return plusNanos(amountToAdd); case MICROS: return plus(amountToAdd / 1000_000, (amountToAdd % 1000_000) * 1000); case MILLIS: return plusMillis(amountToAdd); case SECONDS: return plusSeconds(amountToAdd); case MINUTES: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_MINUTE)); case HOURS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_HOUR)); case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2)); case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY)); } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } 

As you can see, MONTHS and YEARS not supported. But why? With the old java.util.Calendar I can do this easily:

  Calendar c = Calendar.getInstance(); c.setTime(date); c.add(Calendar.YEAR, amount); return c.getTime(); 

The only reason, in my opinion, is that we do not know how many days a month and year because of the leap day on February 29th. But honestly, we also have a second leap . Thus, I think this is a mistake, and all ChronoUnit should be supported. The only question is whether we need to take into account the second and leap day jump. As for my needs, we can simply assume that this month is 30 days and 365 years. I do not need to do something like Calendar.roll() , but that too may satisfy me.

0
source share
1 answer

Let's try something. I take the moment as ZonedDateTime and subtract 10 years in different time zones.

  OffsetDateTime origin = OffsetDateTime.of(2018, 3, 1, 0, 0, 0, 0, ZoneOffset.UTC); Instant originInstant = origin.toInstant(); Instant tenYearsBackKyiv = origin.atZoneSameInstant(ZoneId.of("Europe/Kiev")) .minusYears(10) .toInstant(); long hoursSubtractedKyiv = ChronoUnit.HOURS.between(tenYearsBackKyiv, originInstant); System.out.println("Hours subtracted in Ρ—: " + hoursSubtractedKyiv); Instant tenYearsBackSaoPaulo = origin.atZoneSameInstant(ZoneId.of("America/Sao_Paulo")) .minusYears(10) .toInstant(); long hoursSubtractedSaoPaulo = ChronoUnit.HOURS.between(tenYearsBackSaoPaulo, originInstant); System.out.println("Hours subtracted in SΓ£o Paulo: " + hoursSubtractedSaoPaulo); 

Output:

 Hours subtracted in Ρ—: 87648 Hours subtracted in SΓ£o Paulo: 87672 

As you can see, in Sao Paulo it is deducted 24 hours (1 day more) compared to Kiev (Kiev, Kiev). Perhaps you have already found out that this is because we go from March 1 to February 29 three times in leap years, only twice in Kiev.

The old and now obsolete Calendar class always had a time zone in it, so it knew in which time zone to subtract years (one more thing was happy to give you the result even in situations where it is not clear which result you wanted). The modern classes ZonedDateTime , OffsetDateTime and LocalDateTime can do the same. So use them. Instant does not conceptually have a time zone, so it refuses to perform operations depending on the time zone (I know that it is implemented using UTC, but we should consider this as an irrelevant implementation detail, and not as part of the class interface specification).

Neither the old nor the modern classes take into account the jump, and you are right, so Instant can add and subtract days, hours and minutes.

0
source

Source: https://habr.com/ru/post/1273377/


All Articles