Cela a commencé comme une simple erreur: j'avais YYYY
au lieu de yyyy
dans ma chaîne de format pour un objet SimpleDateFormat
. Mais je suis totalement dérouté par les résultats de mes tests avec la chaîne de format incorrecte.
Ce code:
@Test
public void whatTheHell() {
try {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/YYYY");
Date d1 = sdf.parse("01/07/2016");
Date d2 = sdf.parse("02/08/2016");
Date d3 = sdf.parse("11/29/2027");
System.out.println(d1.toString());
System.out.println(d2.toString());
System.out.println(d3.toString());
} catch (ParseException pe) {
fail("ParseException: " + pe.getMessage());
}
}
produit cette sortie:
Sun Dec 27 00:00:00 PST 2015
Sun Dec 27 00:00:00 PST 2015
Sun Dec 27 00:00:00 PST 2026
J'ai lu la documentation sur le paramètre 'Y' ici: https://docs.Oracle.com/javase/7/docs/api/Java/util/GregorianCalendar.html , mais je continue ne peut pas voir la logique qui fonctionne ici. En particulier, le dernier cas: je peux en quelque sorte comprendre comment les dates de janvier (et peut-être de février) peuvent être traduites en décembre de l'année précédente, mais déplacer la date du 29 novembre de 11 mois en arrière me déroute. Et quelle est la particularité du 27 décembre?
Quelqu'un peut-il expliquer?
PLUS D'INFORMATIONS
@Jan a suggéré que le recours à la méthode toString () pourrait être un problème, j'ai donc défini un format de date pour imprimer YYYY MM dd '-' yyyy MM dd
dans le même code que ci-dessus. Voici la sortie supplémentaire:
2016 12 27 - 2015 12 27
2016 12 27 - 2015 12 27
2027 12 27 - 2026 12 27
C'est simple: le 27 décembre 2015 est le jour 1 de la semaine 1 de la semaine de l'année 2016 (et le 27 décembre 2026 est le jour 1 de la semaine 1 de la semaine de l'année 2027). Cela peut être vérifié en ajoutant ces lignes:
SimpleDateFormat odf = new SimpleDateFormat("YYYY-ww-u");
System.out.println(odf.format(d1));
System.out.println(odf.format(d2));
System.out.println(odf.format(d3));
Si un SimpleDateFormat
affiche une date, il peut utiliser tous les champs: année, mois, jour, jour de la semaine, semaine du mois, semaine de l'année, semaine-année, etc.
Lors de l'analyse, SimpleDateFormat
attend un ensemble de valeurs correspondant: jour, mois, année ou jour de la semaine, semaine dans l'année, semaine -an. Puisque vous avez fourni une semaine-année mais n'avez pas fourni de jour de semaine et de semaine dans l'année, les valeurs de ces valeurs ont été supposées égales à 1.
Les valeurs réelles dépendent de votre environnement local:
(voir https://docs.Oracle.com/javase/7/docs/api/Java/util/GregorianCalendar.html#week_and_year )
Sur mon système (en utilisant les paramètres régionaux de-ch, avec le format "EEE MMM dd HH: mm: ss zzz yyyy - YYYY-ww-u"), j'obtiens
Mo Jan 04 00:00:00 MEZ 2016 - 2016-01-1 Mo Jan 04 00:00:00 MEZ 2016 - 2016-01-1 Mo Jan 04 00:00:00 MEZ 2027 - 2027-01-1
Une semaine peut être définie de différentes manières. Par exemple, aux États-Unis, le premier jour de la semaine est considéré comme le dimanche le plus souvent tandis qu'en Europe et dans de nombreux autres endroits, le premier jour est le lundi.
De même, la semaine d'une année hebdomadaire peut également être définie de différentes manières.
Les classes héritées que vous utilisez utilisent implicitement les définitions spécifiées par un Locale
. Les paramètres régionaux appliqués sont également implicites, en utilisant la valeur par défaut actuelle de la JVM Locale
si vous ne spécifiez pas autrement.
Pour des détails encore plus intéressants sur la difficulté de définir une semaine, voir cette question, Comportement différent de WeekFields sur JVM 8 et JVM 10
Il existe une norme internationale pratique pour la gestion de la date et de l'heure, ISO 8601 .
définition ISO 8601 d'une semaine est:
Je suggère d'utiliser la définition de la norme ISO 8601 autant que possible. Cette définition standard est simple et logique, avec une adoption croissante dans tous les secteurs.
Les classes Java.time offrent un support pour la semaine de l'année en semaine dans la classe WeekFields
.
LocalDate ld = LocalDate.of( 2019 , Month.JANUARY , 1 ) ;
long week = ld.get( WeekFields.ISO.weekOfWeekBasedYear() ) ;
Voir ceci code exécuté en direct sur IdeOne.com .
ld.toString (): 2019-01-01
semaine 1
org.threeten.extra.YearWeek
Mais si vous effectuez une grande partie de ce travail, je suggère d'ajouter la bibliothèque ThreeTen-Extra à votre projet. Vous trouverez la classe YearWeek
utile. Cette classe propose plusieurs méthodes pratiques telles que la génération d'un LocalDate
pour n'importe quel jour de la semaine.
LocalDate ld = LocalDate.of ( 2019 , Month.JANUARY , 1 );
YearWeek yw = YearWeek.from ( ld );
LocalDate startOfWeek = yw.atDay ( DayOfWeek.MONDAY );
ld.toString (): 2019-01-01
yw.toString (): 2019-W01
startOfWeek.toString (): 2018-12-31
Remarquez comment le premier jour de l'année de l'année hebdomadaire de 2019 est une date de l'année civile précédente, 2018 plutôt que 2019.
Le cadre Java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent l'ancien hérité) gênant classes date-heure telles que Java.util.Date
, Calendar
, & SimpleDateFormat
.
Pour en savoir plus, consultez le Tutoriel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 31 .
Le projet Joda-Time , maintenant en mode maintenance , conseille la migration vers les classes Java.time .
Vous pouvez échanger des objets Java.time directement avec votre base de données. Utilisez un pilote JDBC compatible avec JDBC 4.2 ou version ultérieure. Pas besoin de chaînes, pas besoin de Java.sql.*
Des classes.
Où obtenir les classes Java.time?