web-dev-qa-db-fra.com

Java: le moyen le plus simple de soustraire des dates

J'ai créé une classe avec deux champs qui doivent être des dates, start_date et date_passed. Je cherchais le meilleur moyen en Java d’avoir des dates au format YYYY MM DD qui permette une soustraction facile des dates et la possibilité de "maquiller" une date, par exemple dans le futur.

Exemple de ce que j'aimerais que ce soit fait ...

library.circulate_book("Chemistry", **start date here**) //actual date or random date
library.pass_book("Chemistry", **Date Passed here**) //random date such as 5 days after start date
int days_had = Date_Passed - start_date

Jusqu'à présent, j'ai trouvé de nombreuses façons de formater les dates à l'aide des classes Calendriers et Date, mais je n'ai pas encore trouvé de solution qui semble fonctionner, étant donné que la plupart des dates finissent sous forme de chaînes. Toutes les suggestions/petits exemples sont grandement appréciés! En outre, des liens vers des exemples seraient géniaux!

8
Bob

tl; dr

Pour passer d'une date à une autre en ajoutant/soustrayant un nombre de jours.

LocalDate.now(
    ZoneId.of( "Pacific/Auckland" ) 
)
.minusDays( 5 )

Pour calculer le nombre de jours, mois et années écoulés entre deux dates. 

Period.between( start , stop )

L'analyse

Tout d'abord, vous devez analyser vos entrées de chaîne dans des objets date-heure. Ensuite, vous travaillez à préformer votre logique applicative avec ces objets. 

Arrêtez de considérer les valeurs date-heure comme des chaînes, cela vous rendra fou. Nous travaillons avec des objets date-heure dans notre code; nous échangeons des données avec des utilisateurs ou d'autres applications en utilisant une représentation sous forme de chaîne de cet objet date-heure. 

Dans Java 8 et versions ultérieures, utilisez le framework Java.time . Voir Didacticiel

Vous voulez seulement une date, sans heure, afin que nous puissions utiliser la classe LocalDate .

Cette syntaxe amusante à deux points est une référence de la méthode , une manière de dire quelle méthode devrait être appelée par un autre code.

String input = "2015 01 02";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "yyyy MM dd" );
LocalDate localDate = formatter.parse ( input , LocalDate :: from );

Date actuelle

Déterminer la date du jour nécessite un fuseau horaire. Pour un moment donné, la date varie dans le monde entier par zone. 

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate todayTunis = LocalDate.now( z ) ;

Si vous voulez le fuseau horaire actuel par défaut de la machine virtuelle Java, appelez ZoneId.systemDefault.

Soustraire des dates

Cela a déjà été abordé à plusieurs reprises sur StackOveflow.com. Par exemple, Comment soustraire X jours à une date à l'aide d'un calendrier Java? . Pour plus de détails, voir d'autres réponses telles que celle-ci par moi _ et celle-ci par moi _ pour plus de détails. Astuce: "écoulé" est un mot clé de recherche.

En bref, utilisez un Period pour définir un nombre de jours, de mois et d’années standard.

LocalDate weekLater = localDate.plusDays ( 7 );
Period period = Period.between ( localDate , weekLater );
Integer daysElapsed = period.getDays ();

Dump à la console.

System.out.println ( "localDate: " + localDate + " to " + weekLater + " in days: " + daysElapsed );

localDate: 2015-01-02 à 2015-01-09 in days: 7

Notez la limitation selon laquelle Period ne fonctionne qu'avec des jours entiers, c'est-à-dire des valeurs de date uniquement sans heure. C'est ce dont nous avons besoin ici pour cette Question, alors le travail est fait. Si vous aviez des valeurs date-heure (objets ZonedDateTime), utilisez la classe ThreeTen-ExtraDays du projet, comme indiqué dans la question/réponse liée ci-dessus.

10
Basil Bourque

La meilleure façon de faire cela dans Java-8 n'est pas la réponse imparfaite de Basil Bourque mais cette approche:

String startDate = "2016 01 02";
String passedDate = "2016 02 29";

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
LocalDate date1 = LocalDate.parse(startDate, formatter);
LocalDate date2 = LocalDate.parse(passedDate, formatter);

long elapsedDays = ChronoUnit.DAYS.between(date1, date2);
System.out.println(elapsedDays); // 58 (correct)

L'utilisation suggérée de Java.time.Period.getDays() est dangereuse et souvent fausse dès que la durée écoulée dépasse un mois. La variable Period entière est P1M27D, de sorte que ce code interroge uniquement le nombre partiel de jours écoulés (il existe également un mois écoulé):

System.out.println(Period.between(date1, date2).getDays()); // 27 (WRONG!!!)

Il est difficile de trouver une solution satisfaisante utilisant les classes Java.util.Date, GregorianCalendar etc. Vous pouvez utiliser la réponse de Tacktheritrix mais vous devez être conscient du fait que le nombre calculé de jours écoulés peut différer en raison des parties de sous-jour de Java.util.Date et qu'il n'est pas fiable en raison de l'ignorance des commutateurs permettant d'économiser la lumière du jour. (où l'horloge saute d'une heure dans de nombreuses régions du monde).

Note latérale: Au moins 8 bibliothèques externes offrent également de bonnes réponses à votre problème. Mais je pense que votre cas d'utilisation simple ne justifie pas l'intégration d'une bibliothèque supplémentaire à moins que vous ne soyez pas encore sur Java-8. Toute autre solution permettant de compter les jours écoulés entre deux dates ne serait pas plus facile que dans Java-8 - mais similaire. Et puisque vous avez accepté la réponse de Basil Bourque relative à Java-8, je suppose que vous êtes bien sur Java-8, alors je laisse de côté la réponse: comment résoudre votre problème avec d'autres bibliothèques.

8
Meno Hochschild

utiliser Java 8 Date Api ou Joda, pas besoin de nouvelles inventions.

vous pouvez trouver quelques exemples ici: http://examples.javacodegeeks.com/core-Java/java-8-datetime-api-tutorial/

2
Emerson Cod

Voici une réponse utilisant Calendar:

Calendar cal = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();

cal2.setTime(cal.getTime());
cal2.add(Calendar.DAY_OF_YEAR, 5);
System.out.println((cal2.getTimeInMillis() - cal.getTimeInMillis()) / (1000d * 60 * 60 * 24));
1
Evan LaHurd

Si vous êtes coincé avec un Java plus ancien, vous pouvez utiliser SimpleDateFormat.

    //For substraction
    long differenceInMillis = date1.getTime() - date2.getTime();

    //Date Format
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy MM dd");
    String dateAsString = dateFormat.format(date1); //To get a text representation
    Date dateParsed = dateFormat.parse(dateAsString); //To get it back as date
0
liloargana