J’ai un code et un test-case dans une application héritée , qui peuvent être résumés comme suit:
@Test public void testParseDate() throws ParseException { Ssortingng toParse = "Mo Aug 18 11:25:26 MESZ +0200 2014"; Ssortingng 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 en Java 8 et ci-dessous. Cependant, avec Java 9 ou Java 10, cela conduit à une java.text.ParseException: Unparseable date: "Mo Aug 18 11:25:26 MESZ +0200 2014"
.
Pour l’enregistrement : Outre de_DE
, l’exception est également lancée pour les locales de_CH
, de_AT
, de_LU
.
Je suis conscient du fait que le formatage de la date a été modifié avec JDK 9 ( JEP 252 ). Cependant, je considère que cette modification perturbe la rétrocompatibilité. Extrait:
Dans JDK 9, les données CLDR (Common Locale Data Repository) du consortium Unicode sont activées en tant que données de parameters régionaux par défaut, de sorte que vous pouvez utiliser des données de parameters régionaux standard sans aucune autre action.
Dans JDK 8, bien que les données de parameters régionaux CLDR soient regroupées avec le JRE, elles ne sont pas activées par défaut.
Le code qui utilise des services sensibles aux parameters régionaux, tels que la date, l’heure et le formatage des nombres, peut produire des résultats différents avec les données de parameters régionaux CLDR.
Ajouter un .
pour le jour de la semaine ( Mo.
) compense pour cela et le test passerait. Cependant, ce n’est pas une solution réelle pour les anciennes données (sous forme sérialisée telle que XML).
En vérifiant ce post stackoverflow , il semble que le comportement est intentionnel pour les parameters régionaux allemands et peut être atténué en spécifiant java.locale.providers
avec le mode COMPAT
. Cependant, je n’aime pas l’idée de s’appuyer sur une valeur de propriété système pour deux raisons:
Ma question est:
java.locale.providers
/ modifier les données sérialisées existantes ou append / modifier les propriétés du système (comme java.locale.providers
), qui peuvent être oubliées dans différents environnements (serveurs d’applications, bocaux autonomes, …)? Je ne dis pas que c’est une bonne solution, mais cela semble être une solution.
Map dayOfWeekTexts = Map.of(1L, "Mo", 2L, "Di", 3L, "Mi", 4L, "Do", 5L, "Fr", 6L, "Sa", 7L, "So"); Map monthTexts = Map.ofEnsortinges(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); Ssortingng 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 exécutée sur mon Oracle JDK 10.0.1:
2014-08-18T11:25:26+02:00 2014-08-18T11:25:26+02:00[Europe/Berlin]
Là encore, aucune solution intéressante ne peut exister.
java.time
, l’API de date et heure Java moderne, nous permet de spécifier des textes à utiliser pour les champs à la fois pour le formatage et l’parsing. Je l’exploite donc à la fois pour le jour de la semaine et pour le mois, en spécifiant les abréviations sans point qui ont été utilisées avec les anciennes données locales COMPAT ou JRE. J’ai utilisé Java 9 Map.of
et Map.ofEnsortinges
pour créer les cartes dont nous avons besoin. Si cela doit fonctionner aussi avec Java 8, vous devez trouver un autre moyen de remplir les deux cartes, je vous fais confiance.
Si vous avez besoin d’un ancien fichier java.util.Date
(probablement dans une base de code héritée), convertissez comme ceci:
Date date = Date.from(odt.toInstant()); System.out.println("As legacy Date: " + date);
La sortie dans mon fuseau horaire (Europe / Copenhague, correspond probablement à peu près à la vôtre):
As legacy Date: Mon Aug 18 11:25:26 CEST 2014
Je pense que si c’était moi, je penserais à procéder ainsi:
System.setProperty("java.locale.providers", "COMPAT,CLDR");
ainsi, il ne sera oublié dans aucun environnement. Les données locales de COMPAT existent depuis la 1.0 (je crois, au moins à la fin), donc beaucoup de code en dépend (pas seulement le vôtre). Le nom a été changé de JRE à COMPAT en Java 9. Pour moi, cela peut sembler être un plan pour garder les données pendant un bon bout de temps. Selon la documentation sur les premiers access, il sera toujours disponible dans Java 11 (la prochaine version de Java «support à long terme») et sans avertissement de déchéance ou autre. Et si elle devait être supprimée dans une version future de Java, vous pourrez probablement trouver rapidement le problème avant de procéder à la mise à niveau. La valeur formatée en Java 8 était Fr Juni 15 00:20:21 MESZ +0900 2018 Mais elle a changé en Fr. Juin 15 00:20:21 MESZ +0900 2018 EEE comprend. CECI EST PROBLEME DE COMPATIBILITE et peu importe que les anciennes versions de code ne fonctionnent pas dans les nouvelles versions. (Désolé pour le traducteur) Si la chaîne de date est à vous, vous devez append un point pour les nouveaux utilisateurs. Ou faites en sorte que les utilisateurs utilisent Java 8 pour utiliser votre logiciel.
Cela peut ralentir le logiciel, l’utilisation de la méthode de la sous-chaîne est également bonne.
Ssortingng toParse = "Mo Aug 18 11:25:26 MESZ +0200 2014"; Ssortingng str = toParse.subssortingng(0, 2) + "." + toParse.subssortingng(2); Ssortingng 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);
Désolé pour mon mauvais anglais.
Juste pour mentionner: SimpleDateFormat
est une ancienne façon de formater les dates dont BTW n’est pas thread-safe. Depuis Java 8, il existe de nouveaux packages appelés java.time
et java.time.format
, que vous devez utiliser pour java.time.format
dates. Pour vos besoins, vous devez utiliser la classe DateTimeFormatter .