2009-05-31 21 views
5

A partir de una fecha dada, necesito calcular la medianoche de su día. Esto es lo que se me ocurrió. Es tan feo que creo que debe haber una mejor manera.Cálculo de un día dada una fecha

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

Sugerencias?

Kent

+3

Buen Dios - primera Alan Kay, ahora Kent Beck. SO es el lugar para estar ... – duffymo

+0

Es peor que eso, el código que publicaste no cuenta la zona horaria, que puede que te importe o no. – Yishai

+0

simple mira esto [aquí] (http://developer-dot-android.blogspot.com/2012/03/date-into-day-tutorial.html) –

Respuesta

7

usted debe considerar la API fecha incorporada obsoleto. En su lugar, use la API de fecha y hora de Joda.

Aquí hay un reemplazo directo para su método.

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

Aquí es una prueba sencilla:

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

La salida es:

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

Si usted está buscando hora local, eso es lo mejor que vas a conseguir. Y aunque lo consideren feo, hay (potencialmente) mucho detrás de escena.

Si desea UTC medianoche, el siguiente trabajo:

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

Editar: Realmente no recomiendo el uso de fechas locales en código de "producción". Causan más problemas de los que merecen: considere a una persona en la costa oeste de EE. UU. Que repentinamente encuentra que su "día" se reduce en 3 horas porque una computadora de la costa este tiene una idea diferente de la medianoche.

5

JODA podría tener una mejor solución, a costa de otra dependencia de una biblioteca. Estoy mirando su DateMidnight property. Lamento no poder responder con más autoridad, pero tampoco soy usuario de JODA.

0

Creo que la única forma en que vamos a hacer que este código es significativamente mejor por un cambio en la representación. Por ejemplo,

  • representar el día por el sistema de "fecha absoluta" explicado por Nachum Dershowitz y Reingold Ed en Calendrical Calculations.

  • representan el tiempo contando segundos desde la medianoche. O si necesita resolución por debajo del segundo, cuente milisegundos.

De su breve ejemplo que no se puede decir en qué puntos de su programa que se necesita para ser compatible con DateCalendar y clases existentes, o si se puede crear una subclase de utilidad mediante una representación más sano.

0

no ha programado en Java desde hace tiempo, pero que podría ser capaz de llamar a este set method fallecimiento en los valores actuales para el año, mes y día. Aunque por leer un poco cerca, puede que tengas que llamar primero. Esto puede o no ser menos detallado que usar su método actual.

1

JODA es el camino a seguir si usted tiene necesidades naturales graves, por lo menos hasta JSR-310 entre en el JDK (1.7 tal vez, si no es 1.8).

Dicho esto, hay un par de cosas que se pueden hacer para que este código sea un poco más agradable.

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

Eso no ganará ningún premio de rendimiento. Podría hacer un estándar para el bucle basándose en los valores de campo específicos (la clase Calendar tiene un campo FIELD_COUNT que implica que puede hacer algo similar), pero eso corre el riesgo de problemas en las implementaciones de JDK y entre versiones.

0

Esto es solo el complemento del código publicado originalmente. Establece el año, el mes y el día en un nuevo objeto GregorianCalendar, en lugar de borrar todo excepto el año, el mes y el día en la variable de calendario. No es una gran mejora, pero creo que es más claro decir qué campos está copiando, en lugar de qué campos está 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, creo que iría con la biblioteca Joda propuesta por otros.

1

Uso de la biblioteca de date4j:

DateTime start = dt.getStartOfDay(); 
Cuestiones relacionadas