Why Instant does not support operations with ChronoUnit.YEARS?

假装没事ソ 提交于 2020-01-11 19:55:47

问题


This was unexpected to me:

> Clock clock = Clock.systemUTC();

> Instant.now(clock).minus(3, ChronoUnit.DAYS);
java.time.Instant res4 = 2016-10-04T00:57:20.840Z

> Instant.now(clock).minus(3, ChronoUnit.YEARS);
java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Years

As a workaround I have to do this:

> Instant.now(clock).atOffset(ZoneOffset.UTC).minus(3, ChronoUnit.YEARS).toInstant();
java.time.Instant res11 = 2013-10-07T01:02:56.361Z

I am curios why Instant does not support YEARS. Did developers just give up on it?

(In my actual code I tried to subtract a Period.ofYears(3) but the quoted Instant methods are the ones being called in the end).


回答1:


I'm taking a stab at it in what looks to me like something very logical.

Here is the code for the method plus(long, TemporalUnit) (which is used in minus(...)):

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

We can see that the results are calculated by multiplying seconds representation of units, a year cannot be logically and consistently represented by seconds for obvious reasons.


Addition

I can see another obvious reason why : constants used in the method above come from java.time.LocalTime. The constants only define units up to days. No constant above days are defined (in LocalDate and LocalDateTime neither).




回答2:


I guess it happens because Instant does not contain information about time zone. It means that same Instant can be interpreted as different date-time value in different time zones. Let's assume we have Instant which is is represented as 2016.01.01 00:30:00 in, let's say, UTC+2 time zone. The same Instant means 2015.12.31 23:30:00 in UTC+1 time zone. 2016 is a leap year, it's length is 366 days, so in order to get Instant minus 1 year, we have to subtract 366 days from it. But 2015 is not a leap year, it's length is 365 days, so we have to subtract 365 days from Instant. This ambiguity causes the fact that Instant does not support ChronoUnit.YEARS. Similar issue causes Instant to not support ChronoUnit.MONTHS. And probably absence of DST information causes Instant to not support ChronoUnit.WEEKS.



来源:https://stackoverflow.com/questions/39907925/why-instant-does-not-support-operations-with-chronounit-years

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!