Come posso ottenere una data senza orario in Java?


235

Continuando dalla domanda Stack Overflow al programma Java per ottenere la data corrente senza timestamp :

Qual è il modo più efficiente per ottenere un oggetto Date senza l'ora? Esiste un modo diverso da questi due?

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

Aggiornamento :

  1. Sapevo di Joda-Time ; Sto solo cercando di evitare ulteriori librerie per un compito così semplice (credo). Ma sulla base delle risposte finora Joda-Time sembra estremamente popolare, quindi potrei considerarlo.

  2. Per efficienza , voglio dire che voglio evitare la Stringcreazione temporanea di oggetti come usato da method 1, nel frattempo method 2sembra un hack invece di una soluzione.


1
Efficiente? Hai bisogno di più efficienza di quella fornita, ad esempio, con method1?
Johan Sjöberg,

2
Cosa intendi con "efficiente"? Una data è sostanzialmente lunga, non puoi davvero farlo con meno memoria di così. Se intendi "conveniente", il tempo JODA è la strada da percorrere.
millimoose,

3
+1 Esattamente la domanda che avevo.
Alba Mendez,

1
Mi piace il metodo 2. Creare un metodo statico in una classe di utilità e utilizzarlo. Sono stato questo approccio per anni.
Wilson Freitas,

1
Nitpicking sul tuo "aggiornamento 1": se fosse "un compito così semplice", immagino che Sun non sarebbe arrivato a un'API così orribile e inefficiente, e tu (e molte altre persone) non porteresti questa domanda affatto ;-)
Flávio Etrusco

Risposte:


108

Avete assolutamente necessario per l'uso java.util.Date? Vorrei accuratamente consiglia di utilizzare Joda tempo o il java.timepacchetto da Java 8, invece. In particolare, mentre la data e calendario sempre rappresentano un particolare istante di tempo, con tale concetto come "solo una data", Joda Tempo non ha un tipo che rappresenta questa ( LocalDate). Il tuo codice sarà molto più chiaro se sei in grado di utilizzare tipi che rappresentano ciò che stai effettivamente cercando di fare.

Ci sono molte, molte altre ragioni per usare Joda Time o java.timeinvece dei java.utiltipi predefiniti - sono generalmente API molto migliori. È sempre possibile convertire in / da java.util.Datea ai limiti del proprio codice, se necessario, ad esempio per l'interazione con il database.


75
Nelle applicazioni aziendali non abbiamo sempre la possibilità di aggiungere / utilizzare altre librerie. Apprezzo il puntatore a Joda Time, ma in realtà non è una risposta al problema originale di ottenere la parte della data utilizzando Java standard. Grazie. Valorizzare la risposta di Chathuranga.
Noogrub,

3
@noogrub: la risposta di Chathugranga non risponde alla domanda originale, che sta chiedendo come ottenere un Dateoggetto, che risponde formatta una data a una stringa, che non è la stessa cosa. Fondamentalmente, chiedere in quale data Dateè una domanda è insignificante senza ulteriori informazioni: il fuso orario e il sistema di calendario che stai utilizzando.
Jon Skeet,

7
"Nelle applicazioni aziendali non abbiamo sempre la possibilità di aggiungere / utilizzare altre librerie". Veramente ? Stai suggerendo di non poter usare affatto librerie di terze parti?
Brian Agnew,

3
Il commento di @BrianAgnew noogrub sembra essere correlato a vincoli non tecnologici, penso
Jose_GD

3
Dal punto di vista di oggi: " Joda-Time è di fatto la libreria standard di data e ora per Java precedente a Java SE 8. Gli utenti sono ora invitati a migrare su java.time (JSR-310)."
Drux,

66

Ecco cosa ho usato per ottenere la data di oggi con l'ora impostata su 00:00:00:

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

Date today = new Date();

Date todayWithZeroTime = formatter.parse(formatter.format(today));

28
In che modo è diverso dal "metodo 1" già proposto nella domanda originale?
Chris,

Non risolve il fuso orario in cui si verifica (lasciato al fuso orario predefinito arbitrario di JVM).
Darrell Teague,

58

Puoi usare DateUtils.truncate dalla libreria di Apache Commons.

Esempio:

DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH)

3
Se hai intenzione di aggiungere una nuova libreria, lascia che sia Joda invece di Apache Commons.
Dibbeke,

6
+1 @Dibbeke La differenza non è solo che si aggiungerebbe una libreria anziché un'altra. A volte non si vuole imparare una libreria completamente nuova solo per il banale compito di troncare l'ora da una data. O non vuole avere un codice che mescoli la data / il calendario con le date di Joda usando a volte il primo e talvolta il secondo. O non può permettersi / giustificare la sostituzione di tutto il codice ben funzionante basato su data / calendario con un'altra libreria per uno scopo così banale. Mentre suggerisce che Joda è certamente buono in quanto è chiaramente superiore e semplicemente The Right Thing, a volte entra in gioco la vita reale.
SantiBailors

Genio! Mi ha aiutato molto
Thiesen

37

Esiste un modo diverso da questi due?

Si C'è.

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

java.time

Java 8 e versioni successive includono il nuovo pacchetto java.time integrato. Vedi Tutorial . Gran parte della funzionalità java.time è trasferita su Java 6 e 7 in ThreeTen-Backport e ulteriormente adattata ad Android in ThreeTenABP .

Simile a Joda-Time , java.time offre una LocalDateclasse per rappresentare un valore di sola data senza ora del giorno e senza fuso orario.

Si noti che il fuso orario è fondamentale per determinare una data particolare. Allo scoccare della mezzanotte a Parigi, ad esempio, la data è ancora "ieri" a Montréal.

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

Per impostazione predefinita, java.time utilizza lo standard ISO 8601 per generare una rappresentazione in formato stringa di un valore data o data-ora. (Un'altra somiglianza con Joda-Time.) Quindi chiama semplicementetoString() per generare un testo simile 2015-05-21.

String output = today.toString() ; 

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 .

Dove ottenere le classi java.time?

  • Java SE 8 , Java SE 9 e versioni successive
    • Built-in.
    • Parte dell'API Java standard con un'implementazione in bundle.
    • Java 9 aggiunge alcune funzionalità e correzioni minori.
  • Java SE 6 e Java SE 7
    • Gran parte della funzionalità java.time è trasferita su Java 6 e 7 in ThreeTen-Backport .
  • androide
    • Versioni successive di implementazioni di bundle Android delle classi java.time.
    • Per precedenza Android, il ThreeTenABP progetto si adatta ThreeTen-Backport (di cui sopra). Vedi Come usare ThreeTenABP… .

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 .


1
Grazie per aver menzionato il fuso orario . Non mi era venuto in mente che "che giorno è" non è un concetto assoluto.
ToolmakerSteve

@ToolmakerSteve Ottenere la data comporta sempre un fuso orario. Ma il trucco è che se non si specifica un fuso orario, l'attuale fuso orario predefinito della propria JVM viene applicato automaticamente nel determinare la data. Inoltre, l'attuale fuso orario predefinito della JVM può cambiare in qualsiasi momento ! Qualsiasi codice in qualsiasi thread di qualsiasi app all'interno della JVM può chiamare TimeZone.setDefaultdurante il runtime e influire immediatamente su tutti gli altri codici in esecuzione in quella JVM. Morale della storia: specifica sempre un fuso orario.
Basil Bourque,

22

Il modo più semplice:

long millisInDay = 60 * 60 * 24 * 1000;
long currentTime = new Date().getTime();
long dateOnly = (currentTime / millisInDay) * millisInDay;
Date clearDate = new Date(dateOnly);

5
Per me questo è attualmente: "Sab 19 febbraio 01 : 00: 00 CET 2011". Se vuoi usarlo, solo con UTC.
Chris Lercher,

4
La riga 3 non è long dateOnly = (currentTime / millisInDay) * millisInDay;uguale alla scrittura long dateOnly = currentTime;?
Chris,

5
Non lo è, a causa della matematica intera. Pensalo più come Math.floor (currentTime / millisInDay) * millisInDay. Sta effettivamente impostando l'ora alle 00:00:00 in quel modo.
Nicholas Flynt,

2
Questa soluzione probabilmente va bene per la maggior parte delle applicazioni, ma tieni presente che non sempre è vero che un giorno abbia 60 * 60 * 24 * 1000. Ad esempio, puoi avere qualche secondo da saltare in alcuni giorni.
Pierre-Antoine,

1
Questo è probabilmente il modo più ottuso e sconsigliato rispetto ad altri metodi chiari e concisi a 1 e 2 righe.
Darrell Teague,

22

La risposta standard a queste domande è usare Joda Time . L'API è migliore e se stai utilizzando i formattatori e i parser puoi evitare la mancanza non intuitiva di sicurezza del thread di SimpleDateFormat.

L'uso di Joda significa semplicemente che puoi fare:

LocalDate d = new LocalDate();

Aggiornamento :: Usando java 8 questo può essere raggiunto usando

LocalDate date = LocalDate.now();

Il nuovo pacchetto java.time in Java 8 offre anche una LocalDateclasse simile a Joda-Time.
Basil Bourque,

1
Idealmente, DateTimeZonepasseresti un a quel costruttore LocalDate. La determinazione della data corrente dipende dal fuso orario, poiché Parigi inizia una nuova data prima di Montréal. Se si omette il fuso orario, viene applicato il fuso orario predefinito di JVM. Di solito è meglio specificare che fare affidamento sul valore predefinito.
Basil Bourque,

8

Questo è un modo semplice per farlo:

Calendar cal = Calendar.getInstance();
SimpleDateFormat dateOnly = new SimpleDateFormat("MM/dd/yyyy");
System.out.println(dateOnly.format(cal.getTime()));

4
Questa risposta non riesce a rispondere alla domanda. Ottenere una stringa formattata non era l'obiettivo.
Basil Bourque,

7

Non ha senso parlare di una data senza un timestamp per quanto riguarda le routine di data nel runtime java standard, poiché essenzialmente si associa a un millisecondo specifico e non a una data. Detto millisecondo è intrinsecamente associato ad un'ora del giorno che lo rende vulnerabile a problemi di fuso orario come l'ora legale e altre regolazioni del calendario. Vedi Perché sottrarre queste due volte (nel 1927) sta dando uno strano risultato? per un esempio interessante.

Se vuoi lavorare con date anziché millisecondi, devi usare qualcos'altro. Per Java 8 esiste un nuovo set di metodi che fornisce esattamente ciò che chiedi. Per Java 7 e versioni precedenti, utilizzare http://www.joda.org/joda-time/


3
Nota: quegli approcci che dicono "la data a mezzanotte" non gestiscono bene l'ora legale e più fusi orari.
Thorbjørn Ravn Andersen,

Lo confermo, stavo incrementando le date di un giorno nella mia app e ho appreso questo con una segnalazione di bug da parte degli utenti in un fuso orario con l'ora legale (il mio paese non utilizza l'ora legale). Nel giorno in cui inizia l'ora legale la mia app aggiunge 11 ore anziché 12. Forse è meglio usare mezzogiorno come ora per una data "senza orario"?
Jose_GD

1
@Jose_GD Nella migliore delle ipotesi è ancora un trucco. Potresti trovare youtube.com/watch?v=-5wpm-gesOY divertente.
Thorbjørn Ravn Andersen,

@ Thorbjorn, hai ragione, volevo solo evitare JodaTime perché l'aggiunta di una libreria per una sola caratteristica del suono è eccessiva per me. Conoscevo quel video, davvero divertente.
Jose_GD

1
@Jose_GD Il punto era che esiste un caso d'uso reale nella vita in cui il tuo approccio sarebbe considerato un bug. Se ne hai trovato uno, potrebbero essercene altri ... Non so come Joda lo gestisca, ma potresti dare un'occhiata. Nota anche che Java 8 porta una nuova libreria di data e ora (basata sulle esperienze con Joda) che potresti voler esaminare.
Thorbjørn Ravn Andersen,

4

Sicuramente non è il modo più corretto, ma se hai solo bisogno di una soluzione rapida per ottenere la data senza l'ora e non desideri utilizzare una libreria di terze parti, questo dovrebbe fare

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

Avevo solo bisogno della data per scopi visivi e non potevo Joda, quindi ho fatto il substrato.


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

3

Bene, per quanto ne so non c'è modo più semplice per raggiungere questo obiettivo se usi solo il JDK standard.

Ovviamente puoi mettere quella logica in method2 in una funzione statica in una classe helper, come fatto qui nel metodo toBeginningOfTheDay

Quindi puoi abbreviare il secondo metodo per:

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

Oppure, se hai davvero bisogno del giorno corrente in questo formato così spesso, puoi semplicemente avvolgerlo in un altro metodo di supporto statico, rendendolo così un one-liner.


3

Se tutto ciò che vuoi è vedere la data in questo modo "AAAA-MM-GG" senza tutto il resto del disordine, ad esempio "Giovedì 21 maggio 12:08:18 EDT 2015", basta usare java.sql.Date. Questo esempio ottiene la data corrente:

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

Inoltre java.sql.Dateè una sottoclasse di java.util.Date.


3

Se hai solo bisogno della data corrente, senza ora, un'altra opzione è:

DateTime.now().withTimeAtStartOfDay()

1
La domanda non è stata data in nessun momento della giornata. Il risultato è un oggetto data-ora che in effetti ha un'ora del giorno, che di 00:00:00solito è l'ora (può variare in base al fuso orario per anomalie come l' ora legale ). Quindi, come notano altre Risposte, la LocalDateclasse è più appropriata, da Joda-Time (supponendo che tu stia facendo riferimento a Joda-Time - che dovresti notare esplicitamente quando citi classi non in bundle con Java).
Basil Bourque,

3

Usa LocalDate.now()e converti in Datecome di seguito:

Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());

1
L'attuale fuso orario predefinito della JVM può cambiare in qualsiasi momento durante il runtime. Qualsiasi codice in qualsiasi thread di qualsiasi app all'interno della JVM può chiamare TimeZone.setDefault. Il tuo codice chiama ZoneId.systemDefaultdue volte, il primo è implicito LocalDate.now()e il secondo è esplicito atStartOfDay. Tra quei due momenti in fase di esecuzione, l'attuale zona predefinita potrebbe cambiare. Suggerisco di catturare la zona in una variabile e passare ad entrambi i metodi.
Basil Bourque,

2

Se hai bisogno della parte della data solo a scopo di eco, allora

Date d = new Date(); 
String dateWithoutTime = d.toString().substring(0, 10);

1
Non penso che questo sia i18n amichevole
Mark Lapasa l'

2

Che dire di questo?

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

1

Dai un'occhiata a Veyder-time . È un'alternativa semplice ed efficace sia a java.util che a Joda-time. Ha un'API intuitiva e classi che rappresentano solo le date, senza timestamp.


1

Il modo più diretto che sfrutta appieno l'enorme database TimeZone di Java ed è corretto:

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

1

Ecco una soluzione pulita senza conversione in stringa e ritorno, e inoltre non ricalcola il tempo più volte durante il ripristino di ogni componente del tempo a zero. Utilizza anche% (modulo) anziché dividere seguito da moltiplicare per evitare la doppia operazione.

Non richiede dipendenze di terze parti e RISPETTA LA FUSO ORARIO DELL'oggetto Calender passato. Questa funzione restituisce il momento nel tempo alle 12 nel fuso orario della data (Calendario) in cui si passa.

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

Non sono molto convinto che rispetterà l'estate (DST)?
Ole VV,

0

Preferisci non utilizzare le librerie di terze parti il ​​più possibile. So che questo modo è menzionato prima, ma qui è un bel modo pulito:

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

Bene, non usare GregorianCalendar è forse un'opzione!


0

Ho appena fatto questo per la mia app:

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

Livello API 1 Android, nessuna libreria esterna. Rispetta la luce del giorno e il fuso orario predefinito. Nessuna manipolazione di stringhe, quindi penso che in questo modo sia più efficiente della CPU della tua, ma non ho effettuato alcun test.


0

Puoi usare il tempo joda.

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

e chiami con:

Date date = new Date();
System.out.println("Without Time = " + dateWitoutTime(date) + "/n  With time = " + date);
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.