129 votes

Pourquoi la différence entre le 30 mars et le 1er mars 2020 donne-t-elle par erreur 28 jours au lieu de 29 ?

TimeUnit.DAYS.convert(
   Math.abs(
      new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").parse("30-03-2020 00:00:00").getTime() - 
      new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").parse("1-03-2020 00:00:00").getTime()
   ),
   TimeUnit.MILLISECONDS)

Le résultat est 28, alors qu'il devrait être 29.

Le fuseau horaire/le lieu pourrait-il être le problème ?

211voto

Andreas Points 3334

Le problème est qu'en raison du passage à l'heure d'été (le dimanche 8 mars 2020), il y a 28 jours et 23 heures entre ces deux dates. TimeUnit.DAYS.convert(...) tronqué le résultat à 28 jours.

Pour voir le problème (je suis dans le fuseau horaire US Eastern) :

SimpleDateFormat fmt = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
long diff = fmt.parse("30-03-2020 00:00:00").getTime() -
            fmt.parse("1-03-2020 00:00:00").getTime();

System.out.println(diff);
System.out.println("Days: " + TimeUnit.DAYS.convert(Math.abs(diff), TimeUnit.MILLISECONDS));
System.out.println("Hours: " + TimeUnit.HOURS.convert(Math.abs(diff), TimeUnit.MILLISECONDS));
System.out.println("Days: " + TimeUnit.HOURS.convert(Math.abs(diff), TimeUnit.MILLISECONDS) / 24.0);

Sortie

2502000000
Days: 28
Hours: 695
Days: 28.958333333333332

Pour y remédier, utilisez un fuseau horaire qui n'a pas l'heure d'été, par ex. UTC :

SimpleDateFormat fmt = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
long diff = fmt.parse("30-03-2020 00:00:00").getTime() -
            fmt.parse("1-03-2020 00:00:00").getTime();

Sortie

2505600000
Days: 29
Hours: 696
Days: 29.0

41voto

MC Emperor Points 2747

La cause de ce problème est déjà mentionnée dans Réponse d'Andreas .

La question est ce que exactement ce que vous voulez compter. Le fait que vous déclariez que la différence réelle devrait être de 29 au lieu de 28, et que vous demandiez si "L'emplacement/le temps de zone pourrait être un problème" révèle ce que vous voulez réellement compter. Apparemment, vous voulez vous débarrasser de toute différence de fuseau horaire.

Je suppose que vous voulez seulement calculer les jours, sans l'heure et le fuseau horaire.

Java 8

Ci-dessous, dans l'exemple de la façon dont le nombre de jours d'intervalle pourrait être calculé correctement, j'utilise une classe qui représente exactement cela - une date sans heure ni fuseau horaire -. LocalDate .

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d-MM-yyyy HH:mm:ss");
LocalDate start = LocalDate.parse("1-03-2020 00:00:00", formatter);
LocalDate end = LocalDate.parse("30-03-2020 00:00:00", formatter);

long daysBetween = ChronoUnit.DAYS.between(start, end);

Notez que ChronoUnit , DateTimeFormatter et LocalDate nécessitent au moins Java 8, ce qui n'est pas le cas pour vous, d'après le site Web de la Commission européenne. java-7 étiquette. Cependant, elle l'est peut-être pour les futurs lecteurs.

Comme l'a mentionné Ole V.V., il y a aussi le Sac à dos ThreeTen qui reporte la fonctionnalité de l'API Date et Heure de Java 8 vers Java 6 et 7.

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