web-dev-qa-db-fra.com

Pourquoi Instant ne prend pas en charge les opérations avec ChronoUnit.YEARS?

Cela m'était inattendu:

> 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

Comme solution de contournement, je dois faire ceci:

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

Je suis curieux de savoir pourquoi Instant ne prend pas en charge YEARS. Les développeurs ont-ils simplement abandonné?

(Dans mon code actuel, j'ai essayé de soustraire une Period.ofYears(3) mais les méthodes Instant citées sont celles qui sont appelées à la fin).

37
alexandroid

Je m'essaie à ce qui me semble quelque chose de très logique.

Voici le code de la méthode plus(long, TemporalUnit) (qui est utilisée dans 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);
     }

Nous pouvons voir que les résultats sont calculés en multipliant la représentation en secondes des unités, une année ne peut pas être représentée de manière logique et cohérente par des secondes pour des raisons évidentes.


Ajout

Je peux voir une autre raison évidente pour laquelle: les constantes utilisées dans la méthode ci-dessus proviennent de Java.time.LocalTime. Les constantes ne définissent que des unités jusqu'à jours. Aucune constante au-dessus des jours n'est définie (dans LocalDate et LocalDateTime non plus).

23
Yassin Hajaj

Je suppose que cela se produit car Instant ne contient pas d'informations sur le fuseau horaire. Cela signifie qu'un même instantané peut être interprété comme une valeur date-heure différente dans différents fuseaux horaires. Supposons que nous ayons Instant qui est représenté comme 2016.01.01 00:30:00 dans, disons, UTC + 2 fuseau horaire. Le même instant signifie 2015.12.31 23:30:00 en UTC + 1 fuseau horaire. 2016 est une année bissextile, sa durée est de 366 jours, donc pour obtenir Instant moins 1 an, nous devons lui soustraire 366 jours. Mais 2015 n'est pas une année bissextile, sa longueur est de 365 jours, nous devons donc soustraire 365 jours d'Instant. Cette ambiguïté entraîne le fait qu'Instant ne prend pas en charge ChronoUnit.YEARS. Un problème similaire empêche Instant de prendre en charge ChronoUnit.MONTHS. Et probablement l'absence d'informations DST empêche Instant de prendre en charge ChronoUnit.WEEKS.

0
Andrey Koretskyy