web-dev-qa-db-fra.com

Échec de la lettre de modèle de mois de DateTimeFormatter "L"

J'ai remarqué que Java.time.format.DateTimeFormatter n'est pas en mesure d'analyser comme prévu. Voir ci-dessous:

import Java.time.LocalDate;
import Java.time.format.DateTimeFormatter;

public class Play {
  public static void tryParse(String d,String f) {
    try { 
      LocalDate.parse(d, DateTimeFormatter.ofPattern(f)); 
      System.out.println("Pass");
    } catch (Exception x) {System.out.println("Fail");}
  }
  public static void main(String[] args) {
    tryParse("26-may-2015","dd-L-yyyy");
    tryParse("26-May-2015","dd-L-yyyy");
    tryParse("26-may-2015","dd-LLL-yyyy");
    tryParse("26-May-2015","dd-LLL-yyyy");
    tryParse("26-may-2015","dd-M-yyyy");
    tryParse("26-May-2015","dd-M-yyyy");
    tryParse("26-may-2015","dd-MMM-yyyy");
    tryParse("26-May-2015","dd-MMM-yyyy");
  }
}

Seule la dernière tentative avec tryParse("26-May-2015","dd-MMM-yyyy"); "passera". Selon la documentation, LLL devrait être capable d'analyser le format textuel. Notez également la subtile différence entre le "M" majuscule et le "m" minuscule.

C'est vraiment ennuyeux, car je ne peux pas par défaut analyser les chaînes formatées par défaut par Oracle DB

SELECT TO_DATE(SYSDATE,'DD-MON-YYYY') AS dt FROM DUAL;

De même, pour le programme suivant:

import Java.time.LocalDate;
import Java.time.format.DateTimeFormatter;

public class Play {
  public static void output(String f) {
    LocalDate d = LocalDate.now();
    Locale l = Locale.US;
    // Locale l = Locale.forLanguageTag("ru");
    System.out.println(d.format(DateTimeFormatter.ofPattern(f,l)));
  }
  public static void main(String[] args) {
    output("dd-L-yyyy");
    output("dd-LLL-yyyy");
    output("dd-M-yyyy");
    output("dd-MMM-yyyy");
  }
}

J'obtiens en dessous de la sortie:

28-5-2015
28-5-2015
28-5-2015
28-May-2015

Il est clair que le spécificateur de format L ne traite rien de textuel, me semble numérique ...

Cependant, si je change le Locale en Locale.forLanguageTag("ru"), j'obtiens la sortie suivante:

28-5-2015
28-Май-2015
28-5-2015
28-мая-2015

Tout cela est vraiment intéressant, n'êtes-vous pas d'accord?

Mes questions sont les suivantes:

  • Est-il raisonnable pour moi de m'attendre à ce que chacun de ces programmes fonctionne?
  • Devrions-nous au moins soumettre certains d'entre eux comme un bug?
  • Dois-je mal comprendre l'utilisation du spécificateur de modèle L.

Citant une partie de la documentation que j'ai perçue comme "ça compte":

Texte: Le style de texte est déterminé en fonction du nombre de lettres de motif utilisées. Moins de 4 lettres de modèle utiliseront le formulaire court. Exactement 4 lettres de motif utiliseront le formulaire complet. Exactement 5 lettres de motif utiliseront la forme étroite. Les lettres de motif 'L', 'c' et 'q' spécifient la forme autonome des styles de texte.

Nombre: Si le nombre de lettres est un, la valeur est sortie en utilisant le nombre minimum de chiffres et sans remplissage. Sinon, le nombre de chiffres est utilisé comme largeur du champ de sortie, avec la valeur complétée par zéro si nécessaire. Les lettres de modèle suivantes ont des contraintes sur le nombre de lettres. Une seule lettre "c" et "F" peut être spécifiée. Vous pouvez spécifier jusqu'à deux lettres "d", "H", "h", "K", "k", "m" et "s". Vous pouvez spécifier jusqu'à trois lettres "D".

Nombre/texte: Si le nombre de lettres de motif est supérieur ou égal à 3, utilisez les règles de texte ci-dessus. Sinon, utilisez les règles numériques ci-dessus.

[~ # ~] mise à jour [~ # ~]

J'ai fait deux soumissions à Oracle:

  • Demande de correction de bogue pour le problème LLL (Long Form Text): JDK-81148 (ID Oracle Review original: JI-9021661)
  • Demande d'amélioration pour le problème d'analyse du mois en minuscules: ID de révision: 0 (est-ce aussi un bug ??)
25
YoYo

Nom du mois "autonome"

Je crois que "L" est destiné aux langues qui utilisent un mot différent pour le mois lui-même par rapport à la façon dont il est utilisé dans une date. Par exemple:

Locale russian = Locale.forLanguageTag("ru");

asList("MMMM", "LLLL").forEach(ptrn -> 
    System.out.println(ptrn + ": " + ofPattern(ptrn, russian).format(Month.MARCH))
);

Production:

MMMM: марта
LLLL: Март

Il ne devrait y avoir aucune raison d'utiliser "L" au lieu de "M" lors de l'analyse d'une date.

J'ai essayé ce qui suit pour voir quels paramètres régionaux prennent en charge le formatage de nom de mois autonome:

Arrays.stream(Locale.getAvailableLocales())
    .collect(partitioningBy(
                loc -> "3".equals(Month.MARCH.getDisplayName(FULL_STANDALONE, loc)),
                mapping(Locale::getDisplayLanguage, toCollection(TreeSet::new))
    )).entrySet().forEach(System.out::println);

Les langues suivantes obtiennent un nom de mois autonome spécifique aux paramètres régionaux à partir de 'LLLL':

Catalan, chinois, croate, tchèque, finnois, grec, hongrois, italien, lituanien, norvégien, polonais, roumain, russe, slovaque, turc, ukrainien

Toutes les autres langues obtiennent "3" comme nom autonome pour mars.

18
Misha

Selon les javadocs:

Les lettres de modèle "L", "c" et "q" spécifient la forme autonome des styles de texte.

Cependant, je n'ai pas pu trouver grand-chose sur ce que le formulaire "autonome" est censé être. En regardant le code, je vois que l'utilisation de "L" sélectionne TextStyle.SHORT_STANDALONE et selon ce javadoc:

Texte court pour une utilisation autonome, généralement une abréviation. Par exemple, le lundi du jour de la semaine peut afficher "Mon".

Cependant, ce n'est pas ainsi que cela semble fonctionner. Même avec trois lettres, j'obtiens une sortie numérique de ce code:

DateTimeFormatter pattern = DateTimeFormatter.ofPattern ("dd-LLL-yyyy");
System.out.println (pattern.format (LocalDate.now ()));

Modifier

Après une enquête plus approfondie, il semble (aussi près que je peux dire) que les versions "autonomes" de ces codes sont pour quand vous voulez charger vos propres données indépendantes des paramètres régionaux, en utilisant vraisemblablement DateTimeFormatterBuilder. Par conséquent, par défaut, DateTimeFormatter ne contient aucune entrée pour TextStyle.SHORT_STANDALONE.

6
neuronaut

Alors que les autres réponses donnent d'excellentes informations sur la lettre de modèle L et l'analyse de la date, je voudrais ajouter que vous devriez vraiment éviter complètement le problème. N'obtenez pas la date (et l'heure) sous forme de chaîne de votre base de données. Utilisez plutôt un objet datetime approprié.

    String sql = "select sysdate as dt from dual;"
    PreparedStatement stmt = yourDatabaseConnection.prepareStatement(sql);
    ResultSet rs = stmt.executeQuery();
    if (rs.next()) {
        LocalDateTime dateTime = rs.getObject("dt", LocalDateTime.class);
        // do something with dateTime
    }

(Non testé car je n'ai pas de base de données Oracle à portée de main. Veuillez pardonner toute faute de frappe.)

1
Ole V.V.