Mettre en forme une date à l'aide de la nouvelle API de date / heure

118

Je jouais avec la nouvelle API de date et d'heure, mais en exécutant ceci:

public class Test {         
    public static void main(String[] args){
        String dateFormatted = LocalDate.now()
                                        .format(DateTimeFormatter
                                              .ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println(dateFormatted);
    }
}

Il jette:

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay
    at java.time.LocalDate.get0(LocalDate.java:680)
    at java.time.LocalDate.getLong(LocalDate.java:659)
    at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
    at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2543)
    at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
    at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1745)
    at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1719)
    at java.time.LocalDate.format(LocalDate.java:1685)
    at Test.main(Test.java:23)

En regardant le code source de la classe LocalDate, je vois:

  private int get0(TemporalField field) {
        switch ((ChronoField) field) {
            case DAY_OF_WEEK: return getDayOfWeek().getValue();
            case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
            case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
            case DAY_OF_MONTH: return day;
            case DAY_OF_YEAR: return getDayOfYear();
            case EPOCH_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'EpochDay' for get() method, use getLong() instead");
            case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
            case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
            case MONTH_OF_YEAR: return month;
            case PROLEPTIC_MONTH: throw new UnsupportedTemporalTypeException("Invalid field 'ProlepticMonth' for get() method, use getLong() instead");
            case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
            case YEAR: return year;
            case ERA: return (year >= 1 ? 1 : 0);
        }
        throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
    }

Comme il est décrit dans le doc:

Cette méthode créera un formateur basé sur un modèle simple de lettres et de symboles comme décrit dans la documentation de la classe.

Et toutes ces lettres sont définies .

Alors pourquoi DateTimeFormatter.ofPatternne nous permet-il pas d'utiliser des lettres de modèle?

utilisateur2336315
la source

Réponses:

219

LocalDatereprésente juste une date, pas un DateTime. Donc "HH: mm: ss" n'a aucun sens lors du formatage d'un fichier LocalDate. Utilisez LocalDateTimeplutôt un , en supposant que vous souhaitiez représenter à la fois une date et une heure.

James_D
la source
3
Comment puis-je voter pour cette réponse et rejeter le fait qu'il existe à la fois un objet LocalDate et LocalDateTime ...
Xials
Je voudrais simplement travailler avec LocalTime, comment effectuez-vous le formatage sans rencontrer cette exceptionjava.time.temporal.UnsupportedTemporalTypeException: Unsupported field: DayOfWeek
samuel owino
DateTimeFormatter.ofPattern("HH:mm:ss")
Qu'à
36

Je voudrais ajouter les détails suivants à la bonne réponse de @James_D:

Contexte: La plupart des bibliothèques de date et d'heure ( java.util.Calendaren Java, voir aussi .Net-DateTime ou Dateen JavaScript ou DateTimeen Perl) sont basées sur le concept d'un type temporel unique universel universel (en allemand, il y a l'expression poétique " eierlegende Wollmilchsau "). Dans cette conception, il ne peut pas y avoir de champ non pris en charge. Mais le prix est élevé: de nombreux problèmes de temps ne peuvent pas être traités de manière adéquate avec une approche aussi peu flexible, car il est difficile voire impossible de trouver un dénominateur commun pour toutes sortes d'objets temporels.

JSR-310 a choisi une autre façon , à savoir autoriser différents types temporels qui consistent en des ensembles spécifiques au type de champs intégrés pris en charge. La conséquence naturelle est que tous les champs possibles ne sont pas pris en charge par tous les types (et les utilisateurs peuvent même définir leurs propres champs spécialisés). Il est également possible de demander par programme à chaque objet de type TemporalAccessorson ensemble spécifique de champs pris en charge. Car LocalDatenous trouvons:

DAY_OF_WEEK 
ALIGNED_DAY_OF_WEEK_IN_MONTH 
ALIGNED_DAY_OF_WEEK_IN_YEAR 
DAY_OF_MONTH 
DAY_OF_YEAR 
EPOCH_DAY 
ALIGNED_WEEK_OF_MONTH 
ALIGNED_WEEK_OF_YEAR 
MONTH_OF_YEAR 
PROLEPTIC_MONTH 
YEAR_OF_ERA 
YEAR 
ERA 

Il n'y a pas de champ HOUR_OF_DAY qui explique le problème de UnsupportedTemporalTypeException. Et si nous regardons le mappage JSR-310- des symboles de modèle aux champs, nous voyons que le symbole H est mappé à HOUR_OF_DAY non pris en charge:

/** Map of letters to fields. */  
private static final Map<Character, TemporalField> FIELD_MAP = new HashMap<>();
static {
  FIELD_MAP.put('G', ChronoField.ERA);
  FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA);
  FIELD_MAP.put('u', ChronoField.YEAR);
  FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR);
  FIELD_MAP.put('q', IsoFields.QUARTER_OF_YEAR);
  FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR);
  FIELD_MAP.put('L', ChronoField.MONTH_OF_YEAR);
  FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR);
  FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH);
  FIELD_MAP.put('F', ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH);
  FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK);
  FIELD_MAP.put('c', ChronoField.DAY_OF_WEEK);
  FIELD_MAP.put('e', ChronoField.DAY_OF_WEEK);
  FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY);
  FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY);
  FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY);
  FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM);
  FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM);
  FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR);
  FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE);
  FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND);
  FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY);
  FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND);
  FIELD_MAP.put('N', ChronoField.NANO_OF_DAY);    
}

Ce mappage de champ ne signifie pas que le champ est pris en charge par le type concret. L'analyse se déroule en plusieurs étapes. Le mappage de champ n'est que la première étape. La deuxième étape consiste ensuite à analyser un objet brut de type TemporalAccessor. Et enfin analyser les délégués au type cible (ici LocalDate:) et laissez-le décider s'il accepte toutes les valeurs de champ dans l'objet intermédiaire analysé.

Meno Hochschild
la source
4
fr.wiktionary.org/wiki/eierlegende_Wollmilchsau (littéralement «truie-lait-laine pondeuse») Un appareil ou une personne tout-en-un qui n'a (ou prétend avoir) que des attributs positifs et qui peut (ou tente de) faire le travail de plusieurs outils spécialisés. :-)
Trevor Robinson
6

La bonne classe pour moi était celle ZonedDateTimequi comprend à la fois l'heure et le fuseau horaire.

LocalDaten'a pas les informations de temps donc vous obtenez un fichier UnsupportedTemporalTypeException: Unsupported field: HourOfDay.

Vous pouvez utiliser LocalDateTimemais vous n'avez pas les informations de fuseau horaire, donc si vous essayez d'y accéder (même en utilisant l'un des formateurs prédéfinis), vous obtiendrez un fichier UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds.

isapir
la source