Come sottrarre X giorni da una data usando il calendario Java?


180

Qualcuno sa un modo semplice utilizzando il calendario Java per sottrarre X giorni da una data?

Non sono stato in grado di trovare alcuna funzione che mi permetta di sottrarre direttamente X giorni da una data in Java. Qualcuno può indicarmi la giusta direzione?


Cordiali saluti, le vecchie e problematiche classi data-ora come java.util.Calendarora sono legacy , soppiantate dalle classi java.time . Vedi Tutorial di Oracle .
Basil Bourque,

Risposte:


309

Tratto dai documenti qui :

Aggiunge o sottrae il periodo di tempo specificato nel campo del calendario specificato, in base alle regole del calendario. Ad esempio, per sottrarre 5 giorni dall'ora corrente del calendario, puoi ottenerlo chiamando:

Calendar calendar = Calendar.getInstance(); // this would default to now
calendar.add(Calendar.DAY_OF_MONTH, -5).

1
Fai solo attenzione poiché non rotola sempre come ti aspetti.
Carson,

1
Questa risposta ha molti voti positivi, ma è sicura da usare? o questo è meglio: stackoverflow.com/a/10796111/948268
Kuldeep Jain

44
In Calendar.DAY_OF_MONTHquesto caso non lo utilizzeresti poiché non gestirà il rotolo tra i mesi come vorresti. Usa Calendar.DAY_OF_YEARinvece
algoritmi

4
Questo dovrebbe essere al sicuro, a quanto pare quando si aggiunge che non importa se si tratta di DAY_OF_MONTH o DAY_OF_YEAR stackoverflow.com/q/14065198/32453
rogerdpack

@carson quali sono alcuni dei problemi con questo approccio?
tatmanblue,

38

È possibile utilizzare il addmetodo e passargli un numero negativo. Tuttavia, potresti anche scrivere un metodo più semplice che non utilizza la Calendarclasse come la seguente

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

Ciò ottiene il valore data / ora della data (millisecondi dall'epoca) e aggiunge il numero corretto di millisecondi. È possibile passare un numero intero negativo per il parametro days per eseguire la sottrazione. Questo sarebbe più semplice della soluzione di calendario "corretta":

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() );
}

Si noti che entrambe queste soluzioni modificano l' Dateoggetto passato come parametro anziché restituire un valore completamente nuovo Date. Entrambe le funzioni potrebbero essere facilmente modificate per farlo nell'altro modo, se lo si desidera.


3
Non credere .setTime e .add sono metodi statici di Calendar. Dovresti usare la variabile di istanza c.
Edward

@Edward: hai ragione, grazie per aver sottolineato il mio errore, ho corretto il codice in modo che ora funzioni correttamente.
Eli Courtwright,

3
Fate attenzione con il primo modo, per esempio quando si tratta di giorni leapyear potrebbe non riuscire: stackoverflow.com/a/1006388/32453
rogerdpack

Cordiali saluti, le vecchie e problematiche classi data-ora come java.util.Calendarora sono legacy , soppiantate dalle classi java.time . Vedi Tutorial di Oracle .
Basil Bourque,

36

La risposta di Anson funzionerà bene per il semplice caso, ma se hai intenzione di fare calcoli con date più complesse, ti consiglio di dare un'occhiata a Joda Time . Renderà la tua vita molto più semplice.

Cordiali saluti in Joda Time che potresti fare

DateTime dt = new DateTime();
DateTime fiveDaysEarlier = dt.minusDays(5);

1
@ShahzadImam, controlla DateTimeFormat . Ti permetterà di convertire istanze DateTime in stringhe usando formati arbitrari. È molto simile alla classe java.text.DateFormat.
Mike Deck,

1
A partire da Java 8, considera l'utilizzo di java.time docs.oracle.com/javase/8/docs/api/java/time/…
toidiu,

Cordiali saluti, il progetto Joda-Time è ora in modalità manutenzione , con il team che consiglia la migrazione alle classi java.time . Vedi Tutorial di Oracle .
Basil Bourque,

19

tl; dr

LocalDate.now().minusDays( 10 )

Meglio specificare il fuso orario.

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

Dettagli

Le vecchie classi di data e ora in bundle con le prime versioni di Java, come java.util.Date/ .Calendar, hanno dimostrato di essere problematiche, confuse e imperfette. Evitali.

java.time

Java 8 e versioni successive sostituiscono quelle vecchie classi con il nuovo framework java.time. Vedi Tutorial . Definito da JSR 310 , ispirato a Joda-Time ed esteso dal progetto ThreeTen-Extra . Il progetto ThreeTen-Backport esegue il back-port delle classi su Java 6 e 7; il progetto ThreeTenABP su Android.

La domanda è vaga, non chiara se richiede una sola data o una data-ora.

LocalDate

Per una sola data, senza ora del giorno, usa la LocalDateclasse. Si noti che un fuso orario è cruciale nel determinare una data come "oggi".

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

ZonedDateTime

Se intendevi una data-ora, utilizza la Instantclasse per ottenere un momento sulla sequenza temporale in UTC . Da lì, regola un fuso orario per ottenere un ZonedDateTimeoggetto.

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

Tabella dei tipi di data e ora in Java, sia moderni che legacy.


Informazioni su java.time

Il framework java.time è integrato in Java 8 e versioni successive. Queste classi soppiantare la vecchia fastidiosi legacy classi data-time come java.util.Date, Calendar, e SimpleDateFormat.

Il progetto Joda-Time , ora in modalità manutenzione , consiglia la migrazione alle classi java.time .

Per saperne di più, consulta il tutorial Oracle . E cerca Stack Overflow per molti esempi e spiegazioni. La specifica è JSR 310 .

Puoi scambiare oggetti java.time direttamente con il tuo database. Utilizzare un driver JDBC conforme a JDBC 4.2 o successivo. Non c'è bisogno di stringhe, non c'è bisogno di java.sql.*classi.

Dove ottenere le classi java.time?

Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un banco di prova per possibili aggiunte future a java.time. Si possono trovare alcune classi utili, come per esempio Interval, YearWeek, YearQuartere altro .


Questo è un miglioramento molto migliore rispetto alle altre opzioni (è anche molto più recente e fa uso di nuovi metodi). Se stai visitando questo problema ora, questa è la strada da percorrere.
Shourya Bansal,


5

Invece di scrivere il mio addDayscome suggerito da Eli, preferirei usare DateUtilsda Apache . È utile soprattutto quando è necessario utilizzarlo in più punti del progetto.

L'API dice:

addDays(Date date, int amount)

Aggiunge un numero di giorni a una data che restituisce un nuovo oggetto.

Si noti che restituisce un nuovo Dateoggetto e non apporta modifiche al precedente stesso.


2

Può essere fatto facilmente come segue

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());

Questa risposta è sconsiderata, usando terribili vecchie classi di data e ora che sono ora legacy, soppiantate dalle classi java.time. Inoltre, questo codice ignora il problema cruciale del fuso orario, assumendo ingenuamente giorni di 24 ore. Un altro problema è l'utilizzo di una classe di data e ora per risolvere un problema di sola data. L'uso LocalDateè molto più semplice e appropriato.
Basil Bourque,

1

Qualcuno ha consigliato Joda Time così - Ho usato questa classe CalendarDate http://calendardate.sourceforge.net

È un progetto un po 'in competizione con Joda Time, ma molto più semplice in sole 2 classi. È molto utile e ha funzionato benissimo per ciò di cui avevo bisogno poiché non volevo usare un pacchetto più grande del mio progetto. A differenza delle controparti Java, la sua unità più piccola è il giorno, quindi è davvero una data (non averla in millisecondi o qualcosa del genere). Una volta creata la data, tutto ciò che fai per sottrarre è qualcosa come myDay.addDays (-5) per tornare indietro di 5 giorni. Puoi usarlo per trovare il giorno della settimana e cose del genere. Un altro esempio:

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

E:

//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
}

1

Credo che un modo pulito e piacevole per eseguire la sottrazione o l'aggiunta di qualsiasi unità di tempo (mesi, giorni, ore, minuti, secondi, ...) possa essere raggiunto usando la classe java.time.Instant .

Esempio per sottrarre 5 giorni dall'ora corrente e ottenere il risultato come Data:

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

Un altro esempio per sottrarre 1 ora e aggiungere 15 minuti:

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

Se hai bisogno di maggiore precisione, l'istanza misura fino a nanosecondi. Metodi di manipolazione della parte di nanosecondi:

minusNano()
plusNano()
getNano()

Inoltre, tieni presente che la data non è precisa come Instant.


1
O a seconda del gusto, un po 'più breve:Date.from(Instant.now().minus(5, ChronoUnit.DAYS))
Ole VV

1
Bello! Hai ragione. In realtà ho aggiornato la risposta per usare questo e anche mostrare un uso della classe java.time.Duration, che in questo caso è anche molto potente.
Yordan Boev,

0

La seconda soluzione di Eli Courtwright è sbagliata, dovrebbe essere:

Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.DATE, -days);
date.setTime(c.getTime().getTime());

2
Il nome della funzione nella soluzione di Eli è addDays; la sua soluzione è corretta. Se si desidera sottrarre giorni dalla data, si passa un valore negativo per days.
Thomas Upton,

Bene, questo è qualcosa che il programmatore deve specificare quando crea la funzione, no? : P
user178973
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.