50 votes

SimpleDateFormat avec German Locale - Java 8 vs Java 10

J'ai un code et un test dans un héritage de l'application, qui peuvent être résumées comme suit:

@Test
public void testParseDate() throws ParseException {
    String toParse = "Mo Aug 18 11:25:26 MESZ +0200 2014";
    String pattern = "EEE MMM dd HH:mm:ss z Z yyyy";

    DateFormat dateFormatter = new SimpleDateFormat(pattern, Locale.GERMANY);
    Date date = dateFormatter.parse(toParse);

    //skipped assumptions
}

Ce test passe dans Java 8 et ci-dessous. Cependant, avec Java 10 vers le haut, ce qui conduit à un java.text.ParseException: Unparseable date: "Mo Aug 18 11:25:26 MESZ +0200 2014".

Pour l'enregistrement: En plus d' de_DE, l'exception est également lancée pour les paramètres régionaux de_CH, de_AT, de_LU.

Je suis conscient du fait, que le formatage de la Date a été changé avec le JDK 9 (JEP 252). Cependant, je considère que cela est un changement radical de casser la compatibilité ascendante. Extrait:

Dans le JDK 9, le Consortium Unicode Commune de paramètres Régionaux Référentiel de Données (CLDR) de données est activé dans les paramètres régionaux par défaut de données, de sorte que vous pouvez utiliser les paramètres régionaux des données sans aucune autre action.

Dans le JDK 8, bien que la CLDR de données locale est livré avec le JRE, il n'est pas activé par défaut.

Le Code qui utilise les paramètres régionaux des services tels que la date, l'heure et le numéro de mise en forme peuvent produire des résultats différents avec la CLDR de données locale.

L'ajout d'un . pour le jour de la semaine (Mo.) compense ce et test de passage. Cependant, ce n'est pas une vraie solution pour les vieux de données (en forme sérialisée tels que XML).

La vérification de cette stackoverflow post, il semble que le comportement est intentionnel pour la version allemande, et peuvent être atténués par la spécification java.locale.providers avec COMPAT mode. Cependant, je n'aime pas l'idée de s'appuyer sur un système de valeur de la propriété pour deux raisons qu'il peut:

  1. changer dans les prochaines versions du JDK.
  2. être oublié dans différents environnements.

Ma question est:

  • Comment puis-je maintenir la compatibilité ascendante de code hérité avec ce modèle de date, sans ré-écriture / modification de données sérialisées ou l'ajout / modification des propriétés du système (comme java.locale.providers), ce qui peut être oublié dans différents environnements (serveurs d'applications, autonome, pots, ...) ?

22voto

Ole V.V. Points 24677

Je ne dis pas que c'est une bonne solution, mais il semble être un chemin à travers.

    Map<Long, String> dayOfWeekTexts = Map.of(1L, "Mo", 2L, "Di", 
            3L, "Mi", 4L, "Do", 5L, "Fr", 6L, "Sa", 7L, "So");
    Map<Long, String> monthTexts = Map.ofEntries(Map.entry(1L, "Jan"), 
            Map.entry(2L, "Feb"), Map.entry(3L, "Mär"), Map.entry(4L, "Apr"),
            Map.entry(5L, "Mai"), Map.entry(6L, "Jun"), Map.entry(7L, "Jul"),
            Map.entry(8L, "Aug"), Map.entry(9L, "Sep"), Map.entry(10L, "Okt"),
            Map.entry(11L, "Nov"), Map.entry(12L, "Dez"));

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendText(ChronoField.DAY_OF_WEEK, dayOfWeekTexts)
            .appendLiteral(' ')
            .appendText(ChronoField.MONTH_OF_YEAR, monthTexts)
            .appendPattern(" dd HH:mm:ss z Z yyyy")
            .toFormatter(Locale.GERMANY);

    String toParse = "Mo Aug 18 11:25:26 MESZ +0200 2014";
    OffsetDateTime odt = OffsetDateTime.parse(toParse, formatter);
    System.out.println(odt);
    ZonedDateTime zdt = ZonedDateTime.parse(toParse, formatter);
    System.out.println(zdt);

Sortie en cours d'exécution sur mon Oracle JDK 10.0.1:

2014-08-18T11:25:26+02:00
2014-08-18T11:25:26+02:00[Europe/Berlin]

Puis de nouveau, pas de belles solution peut exister.

java.time, le moderne Java date et l'heure de l'API, nous permet de spécifier les textes à utiliser pour les champs pour à la fois le format et l'analyse. J'ai donc l'exploiter à la fois le jour de la semaine et du mois, en précisant les abréviations sans dot qui ont été utilisés avec l'ancien COMPAT ou JRE de données locale. J'ai utilisé le Java 9 Map.of et Map.ofEntries pour la construction de cartes dont nous avons besoin. Si c'est pour travailler dans Java 8 trop, vous devez trouver une autre façon de remplir les deux cartes, je vous fais confiance pour le faire.

Si vous avez besoin d'un old-fashioned java.util.Date (probablement un héritage de la base de code), de convertir, comme ceci:

    Date date = Date.from(odt.toInstant());
    System.out.println("As legacy Date: " + date);

Sortie dans mon fuseau horaire (Europe/Copenhagen, probablement à peu près d'accord avec la vôtre):

As legacy Date: Mon Aug 18 11:25:26 CEST 2014

Proposition pour une stratégie

Je pense que si c'était moi, j'avais envisager de procéder de cette façon:

  1. Attendre. Définir le système de la propriété de l'intérieur Java: System.setProperty("java.locale.providers", "COMPAT,CLDR"); donc il ne sera pas oublié dans n'importe quel environnement. La COMPAT paramètres régionaux des données ont été autour depuis 1.0 (je crois, au moins proche), donc beaucoup de code, il dépend d'elle (pas seulement la vôtre). Le nom a été changé à partir de la JRE à la COMPAT en Java 9. Pour moi, cela peut ressembler à un plan pour garder les données autour pendant un bon moment encore. Selon les premiers accéder à de la documentation , il sera toujours disponible en Java 11 (le côté "long term support" version de Java) et avec aucune dépréciation d'avertissement ou de le comme. Et doit-il être supprimé dans le futur version de Java, vous serez probablement en mesure de trouver assez vite que vous pouvez traiter le problème avant la mise à niveau.
  2. Utiliser ma solution ci-dessus.
  3. Utiliser les paramètres régionaux interface du fournisseur de services qui Basilic Bourque liés. Il n'y a pas de doute que c'est la solution nice dans le cas où la COMPAT données doit être enlevé un peu de temps inconnu dans l'avenir. Vous pouvez même être en mesure de copier le COMPAT paramètres régionaux des données dans vos propres fichiers de sorte qu'ils ne peuvent pas prendre loin de vous, seulement vérifier si il y a des questions de droit d'auteur avant de le faire. La raison pour laquelle je mentionne la solution sympa dernière est vous avez dit que vous n'êtes pas heureux avec le fait d'avoir à définir un système de propriété dans tout environnement où votre programme peut s'exécuter. Aussi loin que je peux dire, en utilisant vos propres données de paramètres régionaux par le biais de la locale interface du fournisseur de services aura encore besoin de vous pour définir le même système de propriété (uniquement à une valeur différente).

2voto

Michael Gantman Points 1936

Juste pour mentionner: est une ancienne façon de formater les `` dates qui BTW n'est pas sans danger thread. Depuis Java 8 il ya de nouveaux paquets appelés et et vous devriez les utiliser pour travailler avec les ```` dates. Pour vos besoins, vous devez utiliser la classe DateTimeFormatter.

0voto

dhkim0800 Points 101

La valeur mise en forme dans java 8 est Fr Juni 15 00:20:21 MESZ +0900 2018 Mais il a changé de Fr. Juni 15 00:20:21 MESZ +0900 2018 EEE comprend . C'EST un PROBLÈME de COMPATIBILITÉ avec et il n'est pas question que les anciennes versions de code ne fonctionne pas dans les versions plus récentes.(Désolé pour le traducteur) Si la date de chaîne est le vôtre, vous devez ajouter un point pour les nouveaux utilisateurs de la version. Ou les utilisateurs à l'utilisation de Java 8 pour l'utilisation de votre logiciel.

Il peut rendre le logiciel plus lentement, en utilisant la méthode sous-chaîne est également bon.

    String toParse = "Mo Aug 18 11:25:26 MESZ +0200 2014";
    String str = toParse.substring(0, 2) + "." + toParse.substring(2);
    String pattern = "EEE MMM dd HH:mm:ss z Z yyyy";

    DateFormat dateFormatter = new SimpleDateFormat(pattern, Locale.GERMANY);
    System.out.println(dateFormatter.format(System.currentTimeMillis()));
    Date date = dateFormatter.parse(str);

Encore désolé pour mon mauvais anglais.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X