Wie bekomme ich ein Datum ohne Zeit in Java?

235

Fahren Sie mit dem Java-Programm " Stapelüberlauf " fort, um das aktuelle Datum ohne Zeitstempel abzurufen :

Was ist der effizienteste Weg, um ein Date-Objekt ohne Zeit zu erhalten? Gibt es einen anderen Weg als diese beiden?

// Method 1
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dateWithoutTime = sdf.parse(sdf.format(new Date()));

// Method 2
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
dateWithoutTime = cal.getTime();

Update :

  1. Ich wusste von Joda-Time ; Ich versuche nur, zusätzliche Bibliothek für eine so einfache (glaube ich) Aufgabe zu vermeiden. Aber basierend auf den bisherigen Antworten scheint Joda-Time äußerst beliebt zu sein, also könnte ich es in Betracht ziehen.

  2. Mit effizient meine ich, dass ich die temporäre Objekterstellung vermeiden möchte, Stringwie sie von verwendet wird method 1. In der Zwischenzeit method 2scheint dies eher ein Hack als eine Lösung zu sein.

Rosdi Kasim
quelle
1
Effizient? Benötigen Sie mehr Effizienz als zB von Methode1?
Johan Sjöberg
2
Was meinst du mit "effizient"? Ein Datum ist im Grunde genommen eine lange Eingabe, man kann dies nicht wirklich in weniger Speicher tun. Wenn Sie "bequem" meinen, ist die JODA-Zeit der richtige Weg.
Millimoose
3
+1 Genau die Frage, die ich hatte.
Alba Mendez
1
Ich mag Methode 2. Erstellen Sie eine statische Methode in einer Utility-Klasse und verwenden Sie sie einfach. Ich bin seit Jahren dieser Ansatz.
Wilson Freitas
1
Nitpicking auf Ihrem "Update 1": Wenn es "eine so einfache Aufgabe" wäre, wäre Sun wohl nicht zu einer so schrecklichen und ineffizienten API gekommen, und Sie (und viele andere Leute) würden diese Frage nicht stellen überhaupt ;-)
Flávio Etrusco

Antworten:

108

Haben Sie unbedingt haben zu verwenden java.util.Date? Ich würde durchaus empfehlen , dass Sie Joda Zeit oder das java.timePaket von Java 8 statt. Insbesondere während Datum und Kalender immer einen bestimmten Zeitpunkt darstellen, ohne solches Konzept als „nur ein Datum“, Joda Zeit hat eine Art haben repräsentiert diese (LocalDate ). Ihr Code wird viel klarer, wenn Sie Typen verwenden können, die das darstellen, was Sie tatsächlich versuchen.

Es gibt viele, viele andere Gründe, Joda Time oder java.timeanstelle der integrierten java.utilTypen zu verwenden - sie sind im Allgemeinen weitaus bessere APIs. Sie können jederzeit java.util.Datean den Grenzen Ihres eigenen Codes nach / von a konvertieren, wenn dies erforderlich ist, z. B. für die Datenbankinteraktion.

Jon Skeet
quelle
75
In Unternehmensanwendungen haben wir nicht immer die Möglichkeit, andere Bibliotheken hinzuzufügen / zu verwenden. Ich schätze den Zeiger auf Joda Time, aber es ist wirklich keine Antwort auf das ursprüngliche Problem, den Datumsanteil mit dem Standard-Java zu erhalten. Vielen Dank. Chathurangas Antwort positiv bewerten.
Noogrub
3
@noogrub: Chathugrangas Antwort beantwortet nicht die ursprüngliche Frage, wie man ein DateObjekt erhält - diese Antwort formatiert ein Datum für eine Zeichenfolge, was nicht dasselbe ist. Grundsätzlich ist die Frage nach dem Datum a Dateeine bedeutungslose Frage ohne weitere Informationen: die Zeitzone und das von Ihnen verwendete Kalendersystem.
Jon Skeet
7
"In Unternehmensanwendungen haben wir nicht immer die Möglichkeit, andere Bibliotheken hinzuzufügen / zu verwenden". Ja wirklich ? Schlagen Sie vor, dass Sie keine Bibliotheken von Drittanbietern verwenden können?
Brian Agnew
3
@ BrianAgnew Noogrub Kommentar scheint mit nicht-technischen Einschränkungen zu
tun zu haben
3
Aus heutiger Sicht: " Joda-Time ist die de facto Standard-Datums- und Zeitbibliothek für Java vor Java SE 8. Benutzer werden nun aufgefordert, auf java.time (JSR-310) zu migrieren."
Drux
65

Folgendes habe ich verwendet, um das heutige Datum mit der eingestellten Zeit zu erhalten 00:00:00:

DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");

Date today = new Date();

Date todayWithZeroTime = formatter.parse(formatter.format(today));
Shobbi
quelle
28
Inwiefern unterscheidet sich dies von der bereits vorgeschlagenen "Methode 1" in der ursprünglichen Frage?
Chris
Es wird nicht angesprochen, in welcher Zeitzone dies auftritt (der beliebigen Standardzeitzone von JVM überlassen).
Darrell Teague
58

Sie können DateUtils.truncate aus der Apache Commons-Bibliothek verwenden.

Beispiel:

DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH)
JoGo
quelle
3
Wenn Sie eine neue Bibliothek hinzufügen möchten, lassen Sie es Joda anstelle von Apache Commons sein.
Dibbeke
6
+1 @Dibbeke Der Unterschied besteht nicht nur darin, dass Sie eine Bibliothek anstelle einer anderen hinzufügen würden. Manchmal möchte man nicht eine ganz neue Bibliothek lernen, nur um die Zeit von einem Datum abzuschneiden. Oder Sie möchten keinen Code, der Datum / Kalender mit Joda-Daten mischt, wobei manchmal die ersteren und manchmal die letzteren verwendet werden. Oder kann es sich nicht leisten / rechtfertigen, den gesamten gut funktionierenden Code auf Datums- / Kalenderbasis durch eine andere Bibliothek für einen so trivialen Zweck zu ersetzen. Während Joda sicherlich gut ist, da es eindeutig überlegen und einfach das Richtige ist,
beginnt
Genius! Hat mir sehr geholfen
Thiesen
37

Gibt es einen anderen Weg als diese beiden?

Ja da ist.

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

java.time

In Java 8 und höher ist das neue Paket java.time integriert. Siehe Tutorial . Ein Großteil der Funktionen von java.time wird in ThreeTen-Backport auf Java 6 & 7 zurückportiert und in ThreeTenABP weiter an Android angepasst .

Ähnlich wie bei Joda-Time bietet java.time aLocalDate Klasse, die einen Nur-Datum-Wert ohne Tageszeit und ohne Zeitzone darstellt.

Beachten Sie, dass die Zeitzone für die Bestimmung eines bestimmten Datums von entscheidender Bedeutung ist. Zum Beispiel um Mitternacht in Paris ist das Datum in Montréal immer noch „gestern“.

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

Standardmäßig verwendet java.time den Standard ISO 8601, um eine Zeichenfolgendarstellung eines Datums oder eines Datums- / Uhrzeitwerts zu generieren. (Eine weitere Ähnlichkeit mit Joda-Time.) Rufen Sie einfach toString()an, um Text wie zu generieren 2015-05-21.

String output = today.toString() ; 

Ü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 auf java.time Klassen .

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

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
1
Vielen Dank für die Erwähnung der Zeitzone . Mir war nicht in den Sinn gekommen, dass "welcher Tag es ist" kein absolutes Konzept ist.
ToolmakerSteve
@ToolmakerSteve Das Abrufen des Datums erfordert immer eine Zeitzone. Der Trick ist jedoch, dass, wenn Sie keine Zeitzone angeben, die aktuelle Standardzeitzone Ihrer JVM bei der Ermittlung des Datums automatisch angewendet wird. Hinzu kommt, dass, die aktuelle Standard - Zeitzone des JVM kann sich ändern , jederzeit ! Jeder Code in einem beliebigen Thread einer App innerhalb der JVM kann zur TimeZone.setDefaultLaufzeit aufgerufen werden und wirkt sich sofort auf alle anderen Codes aus, die in dieser JVM ausgeführt werden. Moral der Geschichte: Geben Sie immer eine Zeitzone an.
Basil Bourque
22

Der einfachste Weg:

long millisInDay = 60 * 60 * 24 * 1000;
long currentTime = new Date().getTime();
long dateOnly = (currentTime / millisInDay) * millisInDay;
Date clearDate = new Date(dateOnly);
römisch
quelle
5
Für mich ist dies derzeit: "Sa 19 Feb 01 : 00: 00 CET 2011". Wenn Sie das verwenden möchten, dann nur mit UTC.
Chris Lercher
4
Ist Zeile 3 nicht long dateOnly = (currentTime / millisInDay) * millisInDay;dasselbe wie Schreiben long dateOnly = currentTime;?
Chris
5
Es ist nicht wegen der ganzzahligen Mathematik. Stellen Sie sich das eher wie Math.floor (currentTime / millisInDay) * millisInDay vor. Auf diese Weise stellt er die Zeit effektiv auf 00:00:00 ein.
Nicholas Flynt
2
Diese Lösung ist wahrscheinlich für die meisten Anwendungen in Ordnung, aber seien Sie gewarnt, dass die Annahme, dass ein Tag 60 * 60 * 24 * 1000 hat, nicht immer wahr ist. Sie können zum Beispiel in einigen Tagen Schaltsekunden haben.
Pierre-Antoine
1
Dies ist wohl der stumpfeste und nicht empfohlene Weg gegenüber anderen klaren und prägnanten 1- und 2-Zeilen-Methoden.
Darrell Teague
22

Die Standardantwort auf diese Fragen ist die Verwendung von Joda Time . Die API ist besser und wenn Sie die Formatierer und Parser verwenden, können Sie den nicht intuitiven Mangel an Thread-Sicherheit von vermeiden SimpleDateFormat.

Mit Joda können Sie einfach Folgendes tun:

LocalDate d = new LocalDate();

Update :: Mit Java 8 kann dies mit erreicht werden

LocalDate date = LocalDate.now();
Brian Agnew
quelle
Das neue Paket java.time in Java 8 bietet auch eine LocalDateähnliche Klasse wie Joda-Time.
Basil Bourque
1
Idealerweise würden Sie a DateTimeZonean diesen LocalDate-Konstruktor übergeben. Die Bestimmung des aktuellen Datums hängt von der Zeitzone ab, da Paris ein neues Datum früher als Montréal beginnt. Wenn Sie die Zeitzone weglassen, wird die Standardzeitzone Ihrer JVM angewendet. Normalerweise besser anzugeben als sich auf die Standardeinstellungen zu verlassen.
Basil Bourque
8

Dies ist eine einfache Methode:

Calendar cal = Calendar.getInstance();
SimpleDateFormat dateOnly = new SimpleDateFormat("MM/dd/yyyy");
System.out.println(dateOnly.format(cal.getTime()));
Tal
quelle
4
Diese Antwort kann die Frage nicht beantworten. Das Erhalten einer formatierten Zeichenfolge war nicht das Ziel.
Basil Bourque
7

Es ist nicht sinnvoll, über ein Datum ohne Zeitstempel in Bezug auf die Datumsroutinen in der Standard-Java-Laufzeit zu sprechen, da es im Wesentlichen auf eine bestimmte Millisekunde und nicht auf ein Datum abgebildet wird. Mit dieser Millisekunde ist an sich eine Tageszeit verbunden, die sie für Zeitzonenprobleme wie Sommerzeit und andere Kalenderanpassungen anfällig macht. Siehe Warum führt das Subtrahieren dieser beiden Male (1927) zu einem seltsamen Ergebnis? für ein interessantes Beispiel.

Wenn Sie mit Datumsangaben anstelle von Millisekunden arbeiten möchten, müssen Sie etwas anderes verwenden. Für Java 8 gibt es eine Reihe neuer Methoden, die genau das bieten, wonach Sie fragen. Verwenden Sie für Java 7 und frühere Versionen http://www.joda.org/joda-time/

Thorbjørn Ravn Andersen
quelle
3
Hinweis: Bei diesen Ansätzen mit der Angabe "Datum um Mitternacht" werden Sommerzeit und mehrere Zeitzonen nicht gut verarbeitet.
Thorbjørn Ravn Andersen
Ich bestätige es, ich habe die Daten in meiner App um einen Tag erhöht und dies durch einen Fehlerbericht von Benutzern in einer Zeitzone mit Sommerzeit erfahren (mein Land verwendet keine Sommerzeit). An dem Tag, an dem die Sommerzeit beginnt, fügt meine App 11 statt 12 Stunden hinzu. Vielleicht ist es besser, Mittag als Stunde für ein Datum ohne Uhrzeit zu verwenden?
Jose_GD
1
@ Jose_GD Es ist bestenfalls noch ein Hack. Vielleicht finden Sie youtube.com/watch?v=-5wpm-gesOY unterhaltsam.
Thorbjørn Ravn Andersen
@ Thorbjorn, du hast recht, wollte nur JodaTime vermeiden, weil das Hinzufügen einer Bibliothek für nur einen Feature-Sound-Overkill für mich. Ich wusste von diesem Video, in der Tat lustig.
Jose_GD
1
@Jose_GD Der Punkt war, dass es einen tatsächlichen Anwendungsfall gibt, in dem Ihr Ansatz als Fehler angesehen wird. Wenn Sie einen gefunden haben, könnte es mehr geben ... Ich weiß nicht, wie Joda damit umgeht, aber Sie könnten einen Blick darauf werfen. Beachten Sie auch, dass Java 8 eine neue Datums- / Uhrzeitbibliothek enthält (basierend auf den Erfahrungen mit Joda), die Sie möglicherweise untersuchen möchten.
Thorbjørn Ravn Andersen
4

Auf jeden Fall nicht der richtigste Weg, aber wenn Sie nur eine schnelle Lösung benötigen, um das Datum ohne Uhrzeit zu erhalten, und keine Bibliothek eines Drittanbieters verwenden möchten, sollte dies der Fall sein

    Date db = db.substring(0, 10) + db.substring(23,28);

Ich brauchte das Datum nur für visuelle Zwecke und konnte Joda nicht, also habe ich einen Teilstring gemacht.

Bamz
quelle
4
// 09/28/2015
System.out.println(new SimpleDateFormat("MM/dd/yyyy").format(Calendar.getInstance().getTime()));

// Mon Sep 28
System.out.println( new Date().toString().substring(0, 10) );

// 2015-09-28
System.out.println(new java.sql.Date(System.currentTimeMillis()));

// 2015-09-28
// java 8
System.out.println( LocalDate.now(ZoneId.of("Europe/Paris")) ); // rest zones id in ZoneId class
blueberry0xff
quelle
3

Soweit ich weiß, gibt es keinen einfacheren Weg, dies zu erreichen, wenn Sie nur das Standard-JDK verwenden.

Sie können diese Logik in Methode2 natürlich in eine statische Funktion in einer Hilfsklasse einfügen , wie hier in der toBeginningOfTheDay-Methode

Dann können Sie die zweite Methode verkürzen auf:

Calendar cal = Calendar.getInstance();
Calendars.toBeginningOfTheDay(cal);
dateWithoutTime = cal.getTime();

Wenn Sie den aktuellen Tag in diesem Format wirklich so oft benötigen, können Sie ihn einfach in eine andere statische Hilfsmethode einwickeln und ihn so zu einem Einzeiler machen.

Enduriel
quelle
3

Wenn Sie nur das Datum wie "JJJJ-MM-TT" ohne all die anderen Unordnung sehen möchten, z. B. "Do 21. Mai 12:08:18 EDT 2015", dann verwenden Sie einfach java.sql.Date. In diesem Beispiel wird das aktuelle Datum abgerufen:

new java.sql.Date(System.currentTimeMillis());

Auch java.sql.Dateist eine Unterklasse von java.util.Date.

BigMac66
quelle
3

Wenn Sie nur das aktuelle Datum ohne Uhrzeit benötigen, ist eine andere Option:

DateTime.now().withTimeAtStartOfDay()
user3037726
quelle
1
In der Frage wurde keine Tageszeit angegeben. Ihr Ergebnis ist ein Datums- / Uhrzeitobjekt, das tatsächlich eine Tageszeit hat, wie dies 00:00:00normalerweise der Fall ist (kann bei Anomalien wie der Sommerzeit je nach Zeitzone variieren ). Wie in anderen Antworten erwähnt, ist die LocalDateKlasse von Joda-Time besser geeignet (vorausgesetzt, Sie verweisen auf Joda-Time - was Sie explizit beachten sollten, wenn Sie Klassen zitieren, die nicht mit Java gebündelt sind).
Basil Bourque
3

Verwenden LocalDate.now()und konvertieren Sie Datewie folgt:

Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
Sahil Chhabra
quelle
1
Die aktuelle Standardzeitzone der JVM kann sich jederzeit zur Laufzeit ändern. Jeder Code in einem beliebigen Thread einer App innerhalb der JVM kann aufgerufen werden TimeZone.setDefault. Ihr Code ruft ZoneId.systemDefaultzweimal auf, der erste ist implizit in LocalDate.now()und der zweite ist explizit mit atStartOfDay. Zwischen diesen beiden Momenten zur Laufzeit kann sich die aktuelle Standardzone ändern. Ich schlage vor, die Zone in einer Variablen zu erfassen und an beide Methoden zu übergeben.
Basil Bourque
2

Wenn Sie den Datumsteil nur zum Echo benötigen, dann

Date d = new Date(); 
String dateWithoutTime = d.toString().substring(0, 10);
manish_s
quelle
1
Ich denke nicht, dass dies i18n freundlich ist
Mark Lapasa
2

Was ist damit?

public static Date formatStrictDate(int year, int month, int dayOfMonth) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(year, month, dayOfMonth, 0, 0, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTime();
}
vitiello.antonio
quelle
1

Schauen Sie sich die Veyder-Zeit an . Es ist eine einfache und effiziente Alternative zu java.util und Joda-time. Es verfügt über eine intuitive API und Klassen, die nur Datumsangaben ohne Zeitstempel darstellen.

Lonerook
quelle
1

Der geradlinigste Weg, der die riesige TimeZone-Datenbank von Java voll ausnutzt und richtig ist:

long currentTime = new Date().getTime();
long dateOnly = currentTime + TimeZone.getDefault().getOffset(currentTime);
TomWolk
quelle
1

Hier ist eine saubere Lösung ohne Konvertierung in String und Back. Außerdem wird die Zeit nicht mehrmals neu berechnet, wenn Sie jede Komponente der Zeit auf Null zurücksetzen. Es verwendet auch% (Modul) anstelle von Teilen und anschließendem Multiplizieren verwendet, um die Doppeloperation zu vermeiden.

Es sind keine Abhängigkeiten von Drittanbietern erforderlich, und es wird die Zeitzone des übergebenen Kalenderobjekts respektiert. Diese Funktion gibt den Zeitpunkt um 12 Uhr in der Zeitzone des von Ihnen übergebenen Datums (Kalenders) zurück.

public static Calendar date_only(Calendar datetime) {
    final long LENGTH_OF_DAY = 24*60*60*1000;
    long millis = datetime.getTimeInMillis();
    long offset = datetime.getTimeZone().getOffset(millis);
    millis = millis - ((millis + offset) % LENGTH_OF_DAY);
    datetime.setTimeInMillis(millis);
    return datetime;
}
Brent Larsen
quelle
Ich bin nicht sehr davon überzeugt, dass es die Sommerzeit (DST) respektieren wird.
Ole VV
0

Verwenden Sie lieber keine Bibliotheken von Drittanbietern. Ich weiß, dass dieser Weg bereits erwähnt wurde, aber hier ist ein schöner, sauberer Weg:

  /*
    Return values:
    -1:    Date1 < Date2
     0:    Date1 == Date2
     1:    Date1 > Date2

    -2:    Error
*/
public int compareDates(Date date1, Date date2)
{
    SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");

    try
    {
        date1 = sdf.parse(sdf.format(date1));
        date2 = sdf.parse(sdf.format(date2));
    }
    catch (ParseException e) {
        e.printStackTrace();
        return -2;
    }

    Calendar cal1 = new GregorianCalendar();
    Calendar cal2 = new GregorianCalendar();

    cal1.setTime(date1);
    cal2.setTime(date2);

    if(cal1.equals(cal2))
    {
        return 0;
    }
    else if(cal1.after(cal2))
    {
        return 1;
    }
    else if(cal1.before(cal2))
    {
        return -1;
    }

    return -2;
}

GregorianCalendar nicht zu verwenden ist vielleicht eine Option!

hehe
quelle
0

Ich habe das gerade für meine App gemacht:

public static Date getDatePart(Date dateTime) {
    TimeZone tz = TimeZone.getDefault();
    long rawOffset=tz.getRawOffset();
    long dst=(tz.inDaylightTime(dateTime)?tz.getDSTSavings():0);
    long dt=dateTime.getTime()+rawOffset+dst; // add offseet and dst to dateTime
    long modDt=dt % (60*60*24*1000) ;

    return new Date( dt
                    - modDt // substract the rest of the division by a day in milliseconds
                    - rawOffset // substract the time offset (Paris = GMT +1h for example)
                    - dst // If dayLight, substract hours (Paris = +1h in dayLight)
    );
}

Android API Level 1, keine externe Bibliothek. Es berücksichtigt Tageslicht und Standardzeitzone. Keine String-Manipulation, daher denke ich, dass dieser Weg CPU-effizienter ist als der Ihre, aber ich habe keine Tests durchgeführt.

Elloco
quelle
0

Sie können Joda-Zeit verwenden.

private Date dateWitoutTime(Date date){
 return new LocalDate(date).toDate()
}

und du rufst an mit:

Date date = new Date();
System.out.println("Without Time = " + dateWitoutTime(date) + "/n  With time = " + date);
Jesús Sánchez
quelle