2009-05-31 11 views
5

Da una determinata data ho bisogno di calcolare la mezzanotte del suo giorno. Ecco cosa mi è venuto in mente. È così brutto che immagino ci debba essere un modo migliore.Calcolo di un giorno dato una data

private Date day(Date creation) { 
    Calendar calendar = Calendar.getInstance(); 
    calendar.setTime(creation); 
    calendar.set(Calendar.HOUR_OF_DAY, 0); 
    calendar.set(Calendar.MINUTE, 0); 
    calendar.set(Calendar.SECOND, 0); 
    calendar.set(Calendar.MILLISECOND, 0); 
    return calendar.getTime(); 
} 

suggerimenti?

Kent

+3

Buon Dio - prima di Alan Kay, ora Kent Beck. SO è il posto dove stare ... – duffymo

+0

È peggio di quello, il codice che hai postato non tiene conto del fuso orario, che potresti o non ti interessa. – Yishai

+0

controllare questo fuori [qui] (http://developer-dot-android.blogspot.com/2012/03/date-into-day-tutorial.html) –

risposta

7

Si dovrebbe considerare l'API data obsoleta obsoleta. Usa invece l'API di data e ora di Joda.

Ecco una sostituzione drop-in per il metodo.

private Date day(Date creation) { 
    return new DateMidnight(creation).toDate(); 
} 

Ecco un semplice test:

public static void main(String[] args) { 
    final Date creation = new Date(); 
    final Date midnight = new Foobar().day(creation); 
    System.out.println("creation = " + creation); 
    System.out.println("midnight = " + midnight); 
} 

L'output è:

creation = Sun May 31 10:09:38 CEST 2009  
midnight = Sun May 31 00:00:00 CEST 2009 
2

Se siete alla ricerca di ora locale, questo è il meglio che si vuole ottenere. E sebbene tu possa considerarlo brutto, c'è (potenzialmente) molto dietro le quinte.

Se si desidera la mezzanotte UTC, il seguente funziona:

public static void main(String[] argv) 
throws Exception 
{ 
    final long MILLIS_PER_DAY = 24 * 3600 * 1000L; 

    long midnightUTC = (System.currentTimeMillis()/MILLIS_PER_DAY) * MILLIS_PER_DAY; 
} 

Edit: davvero non mi consiglia di utilizzare date locali in codice "produzione". Causano più problemi di quanti ne valga la pena - prendi in considerazione una persona sulla costa occidentale degli Stati Uniti che improvvisamente ritaglia il suo "giorno" di 3 ore perché un computer della costa orientale ha un'idea diversa di mezzanotte.

5

JODA potrebbe avere una soluzione migliore, al costo di un'altra dipendenza su una libreria. Sto guardando il suo DateMidnight property. Mi dispiace di non poter rispondere in modo più autoritario, ma non sono un utente JODA.

0

Penso che l'unico modo per rendere questo codice significativamente migliore sia il cambio di rappresentazione. Ad esempio,

  • rappresentare il giorno dal sistema di "data assoluta" spiegato da Nachum Dershowitz e Reingold Ed in Calendrical Calculations.

  • Rappresenta l'ora contando i secondi da mezzanotte. Oppure se hai bisogno di una risoluzione al secondo, conta millisecondi.

Dalla tua breve esempio non posso dire in quali punti nel programma è necessario essere compatibile con le esistenti Date e Calendar classi, o se è possibile creare una sottoclasse utile utilizzando una rappresentazione più sano.

0

Non programmare Java per un po ', ma è possibile chiamare questo set method passando ai valori correnti per anno, mese e giorno. Anche se leggendo un po 'vicino, potresti dover chiamare prima chiaro. Questo può o meno essere meno dettagliato di usare il tuo metodo attuale.

1

JODA è la strada da percorrere se si hanno gravi esigenze di calendario, almeno fino a quando JSR-310 entra nel JDK (1,7 forse, se non 1.8).

Detto questo, ci sono un paio di cose che potrebbero essere fatte per rendere questo codice un po 'più bello.

import static java.util.Calendar.*; 

... 

private static final List<Integer> TIME_FIELDS = 
    Arrays.asList(HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND); 

private Date day(Date creation) { 
    Calendar c = getInstance(); 
    c.setTime(creation); 
    for(int field : TIME_FIELDS) c.set(field, 0); 
    return c.getTime(); 
} 

Questo non vincerà alcun premio per le prestazioni. Si potrebbe fare uno standard per il loop basandosi sui valori dei campi specifici (la classe Calendar ha un campo FIELD_COUNT che implica che si può fare qualcosa del genere) ma che rischia problemi tra le implementazioni JDK e tra le versioni.

0

Questo è solo il complemento del codice pubblicato in origine. Imposta Anno, Mese e Giorno in un nuovo oggetto GregorianCalendar, invece di cancellare tutto tranne Anno, Mese e Giorno nella variabile del calendario. Non è un gran miglioramento, ma penso che sia più chiaro dire quali campi si stanno copiando, invece di quali campi si sta ignorando.

public Date day(Date creation) { 
    Calendar calendar = Calendar.getInstance(); 
    calendar.setTime(creation); 
    return new GregorianCalendar(
      calendar.get(Calendar.YEAR), 
      calendar.get(Calendar.MONTH), 
      calendar.get(Calendar.DAY_OF_MONTH)).getTime(); 
} 

Personalmente, penso che andrei con la libreria Joda proposta da altri.

1

Utilizzando la libreria date4j:

DateTime start = dt.getStartOfDay(); 
Problemi correlati