Comment soustraire X jours d'une date à l'aide du calendrier Java?

180

Quelqu'un connaît-il un moyen simple d'utiliser le calendrier Java pour soustraire X jours d'une date?

Je n'ai trouvé aucune fonction qui me permette de soustraire directement X jours à une date en Java. Quelqu'un peut-il m'indiquer la bonne direction?

fmsf
la source
FYI, les anciennes classes de date-heure gênantes telles que java.util.Calendarmaintenant héritées , supplantées par les classes java.time . Voir le didacticiel d'Oracle .
Basil Bourque

Réponses:

309

Tiré de la documentation ici :

Ajoute ou soustrait la durée spécifiée au champ de calendrier donné, en fonction des règles du calendrier. Par exemple, pour soustraire 5 jours de l'heure actuelle du calendrier, vous pouvez y parvenir en appelant:

Calendar calendar = Calendar.getInstance(); // this would default to now
calendar.add(Calendar.DAY_OF_MONTH, -5).
Anson Smith
la source
1
Faites juste attention car il ne roule pas toujours comme vous vous y attendez.
carson
1
Cette réponse a beaucoup de votes positifs, mais est-elle sûre à utiliser? ou c'est mieux: stackoverflow.com/a/10796111/948268
Kuldeep Jain
44
Vous ne l'utiliseriez pas Calendar.DAY_OF_MONTHdans ce cas car il ne traitera pas le rouleau entre les mois comme vous le souhaiteriez. Utiliser à la Calendar.DAY_OF_YEARplace
algorithmes
4
Cela devrait être sûr, apparemment lorsque vous ajoutez, cela n'a pas d'importance si c'est DAY_OF_MONTH ou DAY_OF_YEAR stackoverflow.com/q/14065198/32453
rogerdpack
@carson Quels sont certains des problèmes avec cette approche?
tatmanblue
38

Vous pouvez utiliser la addméthode et lui passer un nombre négatif. Cependant, vous pouvez également écrire une méthode plus simple qui n'utilise pas la Calendarclasse telle que la suivante

public static void addDays(Date d, int days)
{
    d.setTime( d.getTime() + (long)days*1000*60*60*24 );
}

Cela obtient la valeur d'horodatage de la date (millisecondes depuis l'époque) et ajoute le nombre approprié de millisecondes. Vous pouvez passer un entier négatif pour le paramètre jours pour effectuer la soustraction. Ce serait plus simple que la solution de calendrier "appropriée":

public static void addDays(Date d, int days)
{
    Calendar c = Calendar.getInstance();
    c.setTime(d);
    c.add(Calendar.DATE, days);
    d.setTime( c.getTime().getTime() );
}

Notez que ces deux solutions modifient l' Dateobjet passé en paramètre plutôt que de renvoyer un tout nouveau Date. Chaque fonction peut être facilement modifiée pour le faire dans l'autre sens si vous le souhaitez.

Eli Courtwright
la source
3
Ne croyez pas que .setTime et .add sont des méthodes statiques de Calendar. Vous devriez utiliser la variable d'instance c.
Edward
@Edward: vous avez raison, merci d'avoir signalé mon erreur, j'ai corrigé le code pour qu'il fonctionne maintenant correctement.
Eli Courtwright
3
Soyez prudent avec la première méthode, par exemple lorsque vous traitez avec des jours bissextiles, cela peut échouer: stackoverflow.com/a/1006388/32453
rogerdpack
FYI, les anciennes classes de date-heure gênantes telles que java.util.Calendarmaintenant héritées , supplantées par les classes java.time . Voir le didacticiel d'Oracle .
Basil Bourque
36

La réponse d'Anson fonctionnera bien pour le cas simple, mais si vous comptez faire des calculs de date plus complexes, je vous recommande de consulter Joda Time . Cela vous facilitera la vie.

FYI in Joda Time vous pourriez faire

DateTime dt = new DateTime();
DateTime fiveDaysEarlier = dt.minusDays(5);
Mike Deck
la source
1
@ShahzadImam, consultez DateTimeFormat . Il vous permettra de convertir des instances DateTime en chaînes en utilisant des formats arbitraires. C'est très similaire à la classe java.text.DateFormat.
Mike Deck
1
À partir de Java 8, envisagez d'utiliser java.time docs.oracle.com/javase/8/docs/api/java/time/…
toidiu
Pour info, le projet Joda-Time est maintenant en mode maintenance , l'équipe conseillant la migration vers les classes java.time . Voir le didacticiel d'Oracle .
Basil Bourque
19

tl; dr

LocalDate.now().minusDays( 10 )

Mieux vaut spécifier le fuseau horaire.

LocalDate.now( ZoneId.of( "America/Montreal" ) ).minusDays( 10 )

Détails

Les anciennes classes date-heure fournies avec les premières versions de Java, telles que java.util.Date/ .Calendar, se sont avérées gênantes, déroutantes et défectueuses. Évite-les.

java.time

Java 8 et les versions ultérieures remplacent ces anciennes classes avec le nouveau framework java.time. Voir le didacticiel . Défini par JSR 310 , inspiré de Joda-Time , et prolongé par le projet ThreeTen-Extra . Le projet ThreeTen-Backport back-ports les classes vers Java 6 & 7; le projet ThreeTenABP sur Android.

La question est vague, pas claire si elle demande une date uniquement ou une date-heure.

LocalDate

Pour une date uniquement, sans heure du jour, utilisez la LocalDateclasse. Notez qu'un fuseau horaire est crucial pour déterminer une date telle que «aujourd'hui».

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
LocalDate tenDaysAgo = today.minusDays( 10 );

ZonedDateTime

Si vous vouliez dire une date-heure, utilisez la Instantclasse pour obtenir un moment sur la chronologie en UTC . À partir de là, ajustez-vous à un fuseau horaire pour obtenir un ZonedDateTimeobjet.

Instant now = Instant.now();  // UTC.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
ZonedDateTime tenDaysAgo = zdt.minusDays( 10 );

Tableau des types date-heure en Java, à la fois modernes et hérités.


À propos de java.time

Le framework java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciennes classes de date-heure héritées gênantes telles que java.util.Date,Calendar , et SimpleDateFormat.

Le projet Joda-Time , désormais en mode maintenance , conseille la migration vers les classes java.time .

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

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 cordes, pas besoin dejava.sql.* classes.

Où obtenir les classes java.time?

  • Java SE 8 , Java SE 9 , Java SE 10 et versions ultérieures
    • Intégré.
    • Partie de l'API Java standard avec une implémentation groupée.
    • Java 9 ajoute quelques fonctionnalités et corrections mineures.
  • Java SE 6 et Java SE 7
    • Une grande partie de la fonctionnalité java.time est rétroportée vers Java 6 et 7 dans ThreeTen-Backport .
  • Android
    • Versions ultérieures des implémentations de bundle Android des classes java.time.
    • Pour les versions antérieures d'Android (<26), le projet ThreeTenABP adapte ThreeTen-Backport (mentionné ci-dessus). Voir Comment utiliser ThreeTenABP… .

Le projet ThreeTen-Extra étend java.time avec des classes supplémentaires. Ce projet est un terrain d'essai pour d'éventuels futurs ajouts à java.time. Vous trouverez peut - être des classes utiles ici, comme Interval, YearWeek, YearQuarteret plus .

Basil Bourque
la source
C'est une bien meilleure amélioration par rapport aux autres options (elle est également beaucoup plus récente et utilise de nouvelles méthodes). Si vous consultez ce numéro maintenant, c'est la voie à suivre.
Shourya Bansal le
5

Au lieu d'écrire mon propre addDayscomme suggéré par Eli, je préférerais utiliser DateUtilsd' Apache . C'est pratique surtout lorsque vous devez l'utiliser à plusieurs endroits dans votre projet.

L'API dit:

addDays(Date date, int amount)

Ajoute un nombre de jours à une date renvoyant un nouvel objet.

Notez qu'il renvoie un nouvel Dateobjet et ne modifie pas le précédent lui-même.

Risav Karna
la source
2

Cela peut être fait facilement par ce qui suit

Calendar calendar = Calendar.getInstance();
        // from current time
        long curTimeInMills = new Date().getTime();
        long timeInMills = curTimeInMills - 5 * (24*60*60*1000);    // `enter code here`subtract like 5 days
        calendar.setTimeInMillis(timeInMills);
        System.out.println(calendar.getTime());

        // from specific time like (08 05 2015)
        calendar.set(Calendar.DAY_OF_MONTH, 8);
        calendar.set(Calendar.MONTH, (5-1));
        calendar.set(Calendar.YEAR, 2015);
        timeInMills = calendar.getTimeInMillis() - 5 * (24*60*60*1000);
        calendar.setTimeInMillis(timeInMills);
        System.out.println(calendar.getTime());
rab
la source
Cette réponse est malavisée, utilisant de terribles anciennes classes date-heure qui sont maintenant héritées, supplantées par les classes java.time. En outre, ce code ignore la question cruciale du fuseau horaire, supposant naïvement des jours de 24 heures. Un autre problème consiste à utiliser une classe date-heure pour résoudre un problème de date uniquement. L'utilisation LocalDateest beaucoup plus simple et plus appropriée.
Basil Bourque
1

Quelqu'un a recommandé Joda Time donc - J'ai utilisé cette classe CalendarDate http://calendardate.sourceforge.net

C'est un projet quelque peu concurrent de Joda Time, mais beaucoup plus basique à seulement 2 classes. C'est très pratique et a très bien fonctionné pour ce dont j'avais besoin car je ne voulais pas utiliser un package plus grand que mon projet. Contrairement aux homologues Java, sa plus petite unité est le jour, donc c'est vraiment une date (ne pas l'avoir en quelques millisecondes ou quelque chose). Une fois que vous avez créé la date, tout ce que vous faites pour soustraire est quelque chose comme myDay.addDays (-5) pour revenir 5 jours en arrière. Vous pouvez l'utiliser pour trouver le jour de la semaine et des choses comme ça. Un autre exemple:

CalendarDate someDay = new CalendarDate(2011, 10, 27);
CalendarDate someLaterDay = today.addDays(77);

Et:

//print 4 previous days of the week and today
String dayLabel = "";
CalendarDate today = new CalendarDate(TimeZone.getDefault());
CalendarDateFormat cdf = new CalendarDateFormat("EEE");//day of the week like "Mon"
CalendarDate currDay = today.addDays(-4);
while(!currDay.isAfter(today)) {
    dayLabel = cdf.format(currDay);
    if (currDay.equals(today))
        dayLabel = "Today";//print "Today" instead of the weekday name
    System.out.println(dayLabel);
    currDay = currDay.addDays(1);//go to next day
}
Mikato
la source
1

Je crois qu'une manière propre et agréable d'effectuer la soustraction ou l'addition de n'importe quelle unité de temps (mois, jours, heures, minutes, secondes, ...) peut être obtenue en utilisant la classe java.time.Instant .

Exemple pour soustraire 5 jours de l'heure actuelle et obtenir le résultat comme Date:

new Date(Instant.now().minus(5, ChronoUnit.DAYS).toEpochMilli());

Un autre exemple pour soustraire 1 heure et ajouter 15 minutes:

Date.from(Instant.now().minus(Duration.ofHours(1)).plus(Duration.ofMinutes(15)));

Si vous avez besoin de plus de précision, Instance mesure jusqu'à nanosecondes. Méthodes manipulant une partie nanoseconde:

minusNano()
plusNano()
getNano()

De plus, gardez à l'esprit que la date n'est pas aussi précise qu'Instantané.

Yordan Boev
la source
1
Ou selon les goûts, un peu plus court:Date.from(Instant.now().minus(5, ChronoUnit.DAYS))
Ole VV
1
Agréable! Vous avez raison. J'ai en fait mis à jour la réponse pour utiliser ceci et montrer également une utilisation de la classe java.time.Duration, qui dans ce cas est également très puissante.
Yordan Boev du
0

La deuxième solution d'Eli Courtwright est fausse, elle devrait être:

Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.DATE, -days);
date.setTime(c.getTime().getTime());
utilisateur178973
la source
2
Le nom de la fonction dans la solution d'Eli est addDays; sa solution est correcte. Si vous souhaitez soustraire des jours de la date, vous passez une valeur négative pour days.
Thomas Upton
Eh bien, c'est quelque chose que le programmeur doit spécifier lors de la création de la fonction, non? : P
user178973