358 votes

Nombre de jours entre deux dates en Joda-Time

Comment puis-je trouver la différence en jours entre deux Joda-Time DateTime instances ? Par "différence de jours", je veux dire que si le début est le lundi et la fin le mardi, je m'attends à une valeur de retour de 1, quelle que soit l'heure/minute/seconde des dates de début et de fin.

Days.daysBetween(start, end).getDays() me donne 0 si le début est le soir et la fin le matin.

J'ai également le même problème avec d'autres champs de date et j'espérais qu'il y aurait un moyen générique d'"ignorer" les champs de moindre importance.

En d'autres termes, les mois compris entre février et le 4 mars seraient également égaux à 1, tout comme les heures comprises entre 14 h 45 et 15 h 12. Toutefois, la différence d'heure entre 14 h 01 et 14 h 55 serait égale à 0.

423voto

chrispy Points 3678

Il est regrettable que la réponse à la question withTimeAtStartOfDay soit fausse, mais seulement de manière occasionnelle. Vous voulez :

Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays()

Il s'avère que "minuit/début de journée" signifie parfois 1 heure du matin (l'heure d'été se produit de cette façon dans certains endroits), ce que Days.daysBetween ne gère pas correctement.

// 5am on the 20th to 1pm on the 21st, October 2013, Brazil
DateTimeZone BRAZIL = DateTimeZone.forID("America/Sao_Paulo");
DateTime start = new DateTime(2013, 10, 20, 5, 0, 0, BRAZIL);
DateTime end = new DateTime(2013, 10, 21, 13, 0, 0, BRAZIL);
System.out.println(daysBetween(start.withTimeAtStartOfDay(),
                               end.withTimeAtStartOfDay()).getDays());
// prints 0
System.out.println(daysBetween(start.toLocalDate(),
                               end.toLocalDate()).getDays());
// prints 1

En passant par un LocalDate éluder toute la question.

0 votes

Pouvez-vous fournir un exemple de cas avec des données spécifiques où vous pensez que Days.daysBetween est incorrecte ?

0 votes

Quand vous dites d'utiliser Instant vous ne parlez pas seulement de start.toInstant() Et vous ?

0 votes

@PatrickM Oui, je l'étais. À la réflexion, on ne sait pas exactement quelles contraintes cela vise à imposer, donc je vais retirer cette dernière phrase. Merci !

195voto

Michael Borgwardt Points 181658

Days Classe

Utilisation de la Days avec la classe withTimeAtStartOfDay devrait fonctionner :

Days.daysBetween(start.withTimeAtStartOfDay() , end.withTimeAtStartOfDay() ).getDays()

1 votes

Merci ! J'essayais d'obtenir le comportement de Android.text.format.DateUtils.getRelativeTimeSpanString() avec joda et cela m'a été très utile.

1 votes

Monsieur, en ce qui concerne cette poste la méthode toDateMidnight() du type DateTime est déprécié.

2 votes

Vous devez maintenant utiliser .withTimeAtStartOfDay() au lieu de .toDateMidnight().

90voto

Bozho Points 273663

Vous pouvez utiliser LocalDate :

Days.daysBetween(new LocalDate(start), new LocalDate(end)).getDays()

0 votes

Monsieur, en ce qui concerne cette poste la méthode toDateMidnight() du type DateTime est déprécié.

0 votes

Pourquoi utiliser new LocalDate(date) sur date.toLocalDate() ?

11voto

Basil Bourque Points 8938

Tl;dr

java.time.temporal.ChronoUnit.DAYS.between( 
    earlier.toLocalDate(), 
    later.toLocalDate() 
)

ou

java.time.temporal.ChronoUnit.HOURS.between( 
    earlier.truncatedTo( ChronoUnit.HOURS )  , 
    later.truncatedTo( ChronoUnit.HOURS ) 
)

java.time

Pour info, le Joda-Time Le projet est maintenant en mode de maintenance L'équipe conseille la migration vers le java.time classes.

L'équivalent de Joda-Time DateTime es ZonedDateTime .

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;

Apparemment, vous voulez compter les jours par dates, ce qui signifie que vous voulez ignorer l'heure de la journée. Par exemple, commencer une minute avant minuit et finir une minute après minuit devrait donner un seul jour. Pour ce comportement, extrayez un LocalDate de votre ZonedDateTime . En LocalDate représente une valeur de date uniquement, sans heure du jour et sans fuseau horaire.

LocalDate localDateStart = zdtStart.toLocalDate() ;
LocalDate localDateStop = zdtStop.toLocalDate() ;

Utilisez le ChronoUnit enum pour calculer les jours écoulés ou d'autres unités.

long days = ChronoUnit.DAYS.between( localDateStart , localDateStop ) ;

Tronquer

Quant à votre question sur une façon plus générale de faire ce comptage où vous vous intéressez au delta des heures en tant qu'heure de l'horloge plutôt qu'aux heures complètes en tant qu'intervalles de temps de soixante minutes, utilisez la fonction truncatedTo méthode.

Voici votre exemple de 14 h 45 à 15 h 12 le même jour.

ZoneId z = ZoneId.of( "America/Montreal" ); 
ZonedDateTime start = ZonedDateTime.of( 2017 , 1 , 17 , 14 , 45 , 0 , 0 , z );
ZonedDateTime stop = ZonedDateTime.of( 2017 , 1 , 17 , 15 , 12 , 0 , 0 , z );

long hours = ChronoUnit.HOURS.between( start.truncatedTo( ChronoUnit.HOURS ) , stop.truncatedTo( ChronoUnit.HOURS ) );

1

Cela ne fonctionne pas pendant des jours. Utilisez toLocalDate() dans ce cas.


À propos de java.time

En java.time est intégré à Java 8 et aux versions ultérieures. Ces classes remplacent les anciennes classes héritage les classes de date et d'heure telles que java.util.Date , Calendar , & SimpleDateFormat .

En Joda-Time Le projet, actuellement en mode de maintenance conseille de migrer vers le java.time classes.

Pour en savoir plus, consultez le Tutoriel Oracle . Et recherchez sur Stack Overflow de nombreux exemples et explications. La spécification est JSR 310 .

Vous pouvez échanger java.time directement avec votre base de données. Utilisez un Pilote JDBC conforme à JDBC 4.2 ou plus tard. Pas besoin de ficelles, pas besoin de java.sql.* classes.

Où obtenir les classes java.time ?

  • Java SE 8 , Java SE 9 , Java SE 10 et plus tard
    • Intégré.
    • Fait partie de l'API Java standard avec une mise en œuvre groupée.
    • Java 9 ajoute quelques fonctionnalités et corrections mineures.
  • Java SE 6 y Java SE 7
    • Une grande partie de la fonctionnalité java.time est rétroportée vers Java 6 & 7 dans Trois Dix-Backport .
  • Android
    • Les versions ultérieures d'Android regroupent les implémentations des classes java.time.
    • Pour les Android plus anciens (<26), le ThreeTenABP le projet s'adapte Trois Dix-Backport (mentionné ci-dessus). Voir Comment utiliser ThreeTenABP .

En Trois-Dix-Extra Le projet étend java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour d'éventuels ajouts futurs à java.time. Vous pouvez y trouver des classes utiles telles que Interval , YearWeek , YearQuarter et plus .

En Trois-Dix-Extra Le projet étend java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour d'éventuels ajouts futurs à java.time. Vous pouvez y trouver des classes utiles telles que Interval , YearWeek , YearQuarter et plus .

2voto

JBoy Points 897

La réponse acceptée est de construire deux LocalDate qui sont assez coûteux si vous lisez beaucoup de données. J'utilise ceci :

  public static int getDaysBetween(DateTime earlier, DateTime later)
  {
    return (int) TimeUnit.MILLISECONDS.toDays(later.getMillis()- earlier.getMillis());
  }

En appelant getMillis() vous utilisez des variables déjà existantes.
MILLISECONDS.toDays() puis, utilise un simple calcul arithmétique, ne crée aucun objet.

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