web-dev-qa-db-fra.com

Comment créer l'instant Java à partir d'un modèle?

Considérons un code:

TemporalAccessor date = DateTimeFormatter.ofPattern("yyyy-MM-dd").parse("9999-12-31");
Instant.from(date);

La dernière ligne lève une exception:

Unable to obtain Instant from TemporalAccessor: {},ISO resolved to 9999-12-31 of type Java.time.format.Parsed

Comment créer un motif Instant à partir de yyyy-MM-dd?

16
Cherry

La chaîne "9999-12-31" contient uniquement des informations sur une date. Il ne contient aucune information sur l'heure ou le décalage horaire. En tant que tel, les informations sont insuffisantes pour créer une Instant. (Les autres bibliothèques de date et d'heure sont plus clémentes, mais Java.time évite de remplacer ces valeurs par défaut)

Votre premier choix est d’utiliser une LocalDate au lieu d’un `Instant:

LocalDate date = LocalDate.parse("9999-12-31");

Votre deuxième choix consiste à post-traiter la date pour la convertir en un instant, ce qui nécessite un fuseau horaire, choisi ici pour être Paris:

LocalDate date = LocalDate.parse("9999-12-31");
Instant instant = date.atStartOfDay(ZoneId.of("Europe/Paris")).toInstant();

Votre troisième choix consiste à ajouter le fuseau horaire au formateur et à définir par défaut l'heure:

static final DateTimeFormatter FMT = new DateTimeFormatterBuilder()
    .appendPattern("yyyy-MM-dd")
    .parseDefaulting(ChronoField.NANO_OF_DAY, 0)
    .toFormatter()
    .withZone(ZoneId.of("Europe/Paris"));
Instant instant = FMT.parse("9999-31-12", Instant::from);

(Si cela ne fonctionne pas, assurez-vous de disposer de la dernière version de JDK 8, car un bogue a été corrigé dans cette zone).

Il est à noter qu'aucune de ces possibilités n'utilise directement TemporalAccessor, car ce type est une interface de structure de bas niveau, et non une interface utilisable par la plupart des développeurs d'applications.

36
JodaStephen

Le problème n'est pas le fait que vous utilisez l'année 9999. Le champ Instant.MAX correspond à l'horodatage 1000000000-12-31T23:59:59.999999999Z, de sorte que 9999 en tant qu'année convient.

Traiter avec TemporalAccessors au lieu des types plus riches sémantiquement comme LocalDateTime ou ZonedDateTime revient à utiliser un Map pour modéliser un objet et ses propriétés au lieu d'écrire un class - vous devez vous assurer que la valeur a les champs (comme secondes, nanosecondes, etc.) ) qui sont attendus par quelque chose qui le reçoit, plutôt que de dépendre d'opérations formellement déclarées dans une classe de niveau supérieur pour éviter que les dépendances ne deviennent non satisfaites. 

Dans votre cas, il est probable que l'accesseur temporel contienne les champs de date analysés qui lui ont été donnés, mais qu'il ne possède pas de champ "secondes" requis par la variable Instant. Il est préférable d'utiliser les types les plus riches sur le plan sémantique, tels que LocalDateTime dans la plupart des cas.

Comme vous ne disposez que de champs de date, vous devez l’analyser comme une date, puis ajouter les champs d’heure avant de le convertir en Instant. Voici un moyen, en utilisant LocalDate pour analyser la date:

LocalDate localDate = LocalDate.parse("2016-04-17");
LocalDateTime localDateTime = localDate.atStartOfDay();
Instant instant = localDateTime.toInstant(ZoneOffset.UTC);
15
Hank D
public static void main(String[] args) throws ParseException {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd").parse("2016-12-31").toInstant());
}

le code ci-dessus donne la sortie suivante:

2016-12-31T00: 00: 00Z

j'ai répondu à cette question en utilisant les fonctionnalités (méthode 'toInstant') de Java 8. J'espère que cela répond à votre question ...

4
Abhishek

Soit vous ne vous intéressez qu'à la date elle-même (31 décembre 9999), auquel cas le type approprié serait un LocalDate:

LocalDate date = LocalDate.parse("9999-12-31");

Ou vous voulez une Instant, auquel cas vous devez définir une heure et un fuseau horaire, par exemple, 00:00 à Tokyo:

Instant instant = date.atStartOfDay(ZoneId.of("Asia/Tokyo")).toInstant();
0
assylias