Wie subtrahiere ich X Tage von einem Datum mit dem Java-Kalender?

179

Kennt jemand eine einfache Möglichkeit, mit Java-Kalender X Tage von einem Datum zu subtrahieren?

Ich konnte keine Funktion finden, mit der ich X Tage direkt von einem Datum in Java abziehen kann. Kann mich jemand in die richtige Richtung weisen?

fmsf
quelle
Zu Ihrer Information , die problematischen alten Datums- / Uhrzeitklassen, wie sie java.util.Calendarjetzt Legacy sind , werden durch die Klassen java.time ersetzt . Siehe Tutorial von Oracle .
Basil Bourque

Antworten:

307

Aus den Dokumenten hier entnommen :

Addiert oder subtrahiert die angegebene Zeit zum angegebenen Kalenderfeld, basierend auf den Regeln des Kalenders. Um beispielsweise 5 Tage von der aktuellen Uhrzeit des Kalenders abzuziehen, können Sie dies erreichen, indem Sie Folgendes aufrufen:

Calendar calendar = Calendar.getInstance(); // this would default to now
calendar.add(Calendar.DAY_OF_MONTH, -5).
Anson Smith
quelle
1
Seien Sie vorsichtig, da es nicht immer so rollt, wie Sie es erwarten.
Carson
1
Diese Antwort hat viele positive Stimmen, aber ist sie sicher zu verwenden? oder das ist besser: stackoverflow.com/a/10796111/948268
Kuldeep Jain
44
Sie würden Calendar.DAY_OF_MONTHin diesem Fall nicht verwenden , da die Rolle zwischen den Monaten nicht so verarbeitet wird, wie Sie es möchten. Verwenden Sie Calendar.DAY_OF_YEARstattdessen
Algorithmen
4
Dies sollte sicher sein, anscheinend spielt es beim Hinzufügen keine Rolle, ob es DAY_OF_MONTH oder DAY_OF_YEAR stackoverflow.com/q/14065198/32453
rogerdpack
@carson was sind einige der Probleme mit diesem Ansatz?
Tatmanblue
38

Sie können die addMethode verwenden und eine negative Zahl übergeben. Sie können jedoch auch eine einfachere Methode schreiben, die die CalendarKlasse nicht verwendet , wie die folgende

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

Dadurch wird der Zeitstempelwert des Datums (Millisekunden seit der Epoche) abgerufen und die richtige Anzahl von Millisekunden hinzugefügt. Sie können eine negative Ganzzahl für den Parameter days übergeben, um die Subtraktion durchzuführen. Dies wäre einfacher als die "richtige" Kalenderlösung:

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

Beachten Sie, dass beide Lösungen Datedas als Parameter übergebene Objekt ändern, anstatt ein völlig neues zurückzugeben Date. Jede Funktion kann leicht geändert werden, um sie auf Wunsch auch andersherum auszuführen.

Eli Courtwright
quelle
3
Glauben Sie nicht, dass .setTime und .add statische Methoden des Kalenders sind. Sie sollten die Instanzvariable c verwenden.
Edward
@ Edward: Sie haben Recht, danke, dass Sie auf meinen Fehler hingewiesen haben. Ich habe den Code so korrigiert, dass er jetzt ordnungsgemäß funktioniert.
Eli Courtwright
3
Seien Sie vorsichtig mit dem ersten Weg, zum Beispiel wenn es um Leapyear-Tage geht, kann es fehlschlagen: stackoverflow.com/a/1006388/32453
rogerdpack
Zu Ihrer Information , die problematischen alten Datums- / Uhrzeitklassen, wie sie java.util.Calendarjetzt Legacy sind , werden durch die Klassen java.time ersetzt . Siehe Tutorial von Oracle .
Basil Bourque
36

Ansons Antwort wird für den einfachen Fall gut funktionieren, aber wenn Sie komplexere Datumsberechnungen durchführen möchten, würde ich empfehlen, Joda Time zu überprüfen . Es wird Ihr Leben viel einfacher machen.

Zu Ihrer Information in Joda Time, die Sie tun könnten

DateTime dt = new DateTime();
DateTime fiveDaysEarlier = dt.minusDays(5);
Mike Deck
quelle
1
@ShahzadImam, sehen Sie sich DateTimeFormat an . Damit können Sie DateTime-Instanzen in Zeichenfolgen in beliebigen Formaten konvertieren. Es ist der Klasse java.text.DateFormat sehr ähnlich.
Mike Deck
1
Ab Java 8 sollten Sie java.time docs.oracle.com/javase/8/docs/api/java/time/…
toidiu
Zu Ihrer Information , das Joda-Time- Projekt befindet sich jetzt im Wartungsmodus. Das Team empfiehlt die Migration zu den Klassen java.time . Siehe Tutorial von Oracle .
Basil Bourque
19

tl; dr

LocalDate.now().minusDays( 10 )

Besser Zeitzone angeben.

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

Einzelheiten

Die alten Datums- / Uhrzeitklassen, die mit früheren Java-Versionen wie java.util.Date/ gebündelt sind .Calendar, haben sich als problematisch, verwirrend und fehlerhaft erwiesen. Vermeide sie.

java.time

Java 8 und höher ersetzt diese alten Klassen durch das neue java.time-Framework. Siehe Tutorial . Definiert von JSR 310 , inspiriert von Joda-Time und erweitert durch das ThreeTen-Extra- Projekt. Das ThreeTen-Backport-Projekt portiert die Klassen zurück zu Java 6 & 7; das ThreeTenABP-Projekt für Android.

Die Frage ist vage und nicht klar, ob sie nur ein Datum oder eine Uhrzeit erfordert.

LocalDate

Verwenden Sie die LocalDateKlasse nur für ein Datum ohne Uhrzeit . Beachten Sie, dass eine Zeitzone für die Bestimmung eines Datums wie "Heute" von entscheidender Bedeutung ist.

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

ZonedDateTime

Wenn Sie eine Datums- und Uhrzeitangabe gemeint haben, verwenden Sie die InstantKlasse, um einen Moment auf der Zeitachse in UTC abzurufen . Passen Sie von dort aus eine Zeitzone an, um ein ZonedDateTimeObjekt zu erhalten.

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

Tabelle der Datums- und Uhrzeittypen in Java, sowohl modern als auch alt.


Über java.time

Das java.time- Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Legacy - Datum-Zeit - Klassen wie java.util.Date, Calendar, & SimpleDateFormat.

Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .

Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .

Sie können java.time- Objekte direkt mit Ihrer Datenbank austauschen . Verwenden Sie einen JDBC-Treiber, der mit JDBC 4.2 oder höher kompatibel ist . Keine Notwendigkeit für Zeichenfolgen, keine Notwendigkeit für java.sql.*Klassen.

Woher bekomme ich die java.time-Klassen?

Das ThreeTen-Extra- Projekt erweitert java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von java.time. Sie können einige nützliche Klassen hier wie finden Interval, YearWeek, YearQuarter, und mehr .

Basil Bourque
quelle
Dies ist eine viel bessere Verbesserung gegenüber den anderen Optionen (es ist auch viel neuer und verwendet neue Methoden). Wenn Sie diese Ausgabe jetzt besuchen, ist dies der richtige Weg.
Shourya Bansal
5

Anstatt meine eigenen zu schreiben, addDayswie von Eli vorgeschlagen, würde ich lieber DateUtilsvon Apache verwenden . Dies ist besonders praktisch, wenn Sie es an mehreren Stellen in Ihrem Projekt verwenden müssen.

Die API sagt:

addDays(Date date, int amount)

Fügt einem Datum, das ein neues Objekt zurückgibt, eine Anzahl von Tagen hinzu.

Beachten Sie, dass ein neues DateObjekt zurückgegeben wird und keine Änderungen am vorherigen selbst vorgenommen werden.

Risav Karna
quelle
2

Dies kann auf einfache Weise wie folgt durchgeführt werden

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
quelle
Diese Antwort ist schlecht beraten, da schreckliche alte Datums- / Uhrzeitklassen verwendet werden, die jetzt Legacy sind und durch die Klassen java.time ersetzt werden. Außerdem ignoriert dieser Code das entscheidende Problem der Zeitzone und geht naiv von 24-Stunden-Tagen aus. Ein weiteres Problem ist die Verwendung einer Datums- / Uhrzeitklasse, um ein Problem nur mit Datum zu lösen. Die Verwendung LocalDateist viel einfacher und angemessener.
Basil Bourque
1

Jemand hat Joda Time empfohlen - ich habe diese CalendarDate- Klasse http://calendardate.sourceforge.net verwendet

Es ist ein etwas konkurrierendes Projekt für Joda Time, aber viel grundlegender in nur 2 Klassen. Es ist sehr praktisch und hat hervorragend für das funktioniert, was ich brauchte, da ich kein größeres Paket als mein Projekt verwenden wollte. Im Gegensatz zu den Java-Gegenstücken ist die kleinste Einheit der Tag, also ist es wirklich ein Datum (ohne Millisekunden oder so). Sobald Sie das Datum erstellt haben, müssen Sie nur noch myDay.addDays (-5) subtrahieren, um 5 Tage zurück zu gehen. Sie können es verwenden, um den Wochentag und ähnliche Dinge zu finden. Ein anderes Beispiel:

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

Und:

//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
quelle
1

Ich glaube, dass mit der Klasse java.time.Instant eine saubere und nette Methode zum Subtrahieren oder Addieren einer beliebigen Zeiteinheit (Monate, Tage, Stunden, Minuten, Sekunden, ...) erreicht werden kann .

Beispiel für das Subtrahieren von 5 Tagen von der aktuellen Zeit und das Abrufen des Ergebnisses als Datum:

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

Ein weiteres Beispiel zum Subtrahieren von 1 Stunde und Addieren von 15 Minuten:

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

Wenn Sie mehr Genauigkeit benötigen, misst Instance bis zu Nanosekunden. Methoden zur Manipulation des Nanosekunden-Teils:

minusNano()
plusNano()
getNano()

Beachten Sie auch, dass das Datum nicht so genau ist wie Instant.

Yordan Boev
quelle
1
Oder je nach Geschmack etwas kürzer:Date.from(Instant.now().minus(5, ChronoUnit.DAYS))
Ole VV
1
Nett! Du hast recht. Ich habe die Antwort tatsächlich aktualisiert, um dies zu verwenden und auch eine Verwendung der Klasse java.time.Duration anzuzeigen, die in diesem Fall ebenfalls sehr wirksam ist.
Yordan Boev
0

Eli Courtwright zweite Lösung ist falsch, es sollte sein:

Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.DATE, -days);
date.setTime(c.getTime().getTime());
user178973
quelle
2
Der Name der Funktion in Elis Lösung lautet addDays: seine Lösung ist richtig. Wenn Sie Tage vom Datum abziehen möchten, übergeben Sie einen negativen Wert für days.
Thomas Upton
Nun, das muss der Programmierer beim Erstellen der Funktion angeben, nicht wahr? : P
user178973