2010-07-21 21 views
25

estoy revisando algo de código en el trabajo y encontré una inconsistencia en la forma en que el código controla la adición de 1 semana a la hora actual y se preguntaba si había alguna razón por la que uno realmente debe preferirse sobre el otro:Agregar 1 semana a una fecha, ¿qué camino es el preferido?

La primera era un método de utilidad:

public static Date addDaysToDate(final Date date, int noOfDays) { 
    Date newDate = new Date(date.getTime()); 

    GregorianCalendar calendar = new GregorianCalendar(); 
    calendar.setTime(newDate); 
    calendar.add(Calendar.DATE, noOfDays); 
    newDate.setTime(calendar.getTime().getTime()); 

    return newDate; 
} 

Y el segundo aritmética simple milisegundos utilizado:

long theFuture = System.currentTimeMillis() + (86400 * 7 * 1000); 
Date nextWeek = new Date(theFuture); 

el segundo método utiliza obviamente 'números mágicos' para definir a la semana, pero esto podría ser movida d a una constante MILLISECONDS_IN_ONE_WEEK = 86400 * 7 * 1000 Entonces, aparte de eso, ¿hay alguna razón por la que uno de estos métodos deba preferirse al otro?

Básicamente quiero cambiar el código para que sea coherente en todo momento, pero no estoy del todo seguro de cuál eliminar. Entonces, cualquier argumento de una forma u otra sería útil.

+2

* tos * Use Joda-Time. 'DateTime newDate = date.plusWeeks (1); ' – ColinD

+7

El código se ejecuta en un dispositivo con Windows Mobile utilizando una JVM basada principalmente en Java 1.2. Joda solo se ha probado contra 1.4 y versiones posteriores, por lo que no quiero agregar una biblioteca de terceros que realmente no fue diseñada para ejecutarse en la plataforma que estoy usando. Pero gracias por la sugerencia. – DaveJohnston

Respuesta

22

Los dos métodos se comportarán de manera diferente en los límites de ahorro de luz diurna.El primer método continuará regresando a la misma hora del día, independientemente del estado de ahorro de luz natural. El segundo método devolverá los tiempos que varían una hora en cada dirección a medida que comienza y finaliza el horario de verano.

0

Cuanto más general, más útil será. Si siempre agregas una semana, elegiría el segundo método. Si tiene diferentes adiciones, elegí la primera, quizás reemplazando días por segundos o incluso milésimas si es necesario.

0

El primero será más lento, por lo que si el rendimiento es un problema, el segundo es mejor.

+0

Se ejecuta en un dispositivo con Windows Mobile, por lo que el rendimiento es definitivamente una preocupación. ¿Qué tanto impacto crees que tendría (más o menos)? – DaveJohnston

+0

Depende de la frecuencia con la que se llama, ese tipo de cosas. Para tener una idea, necesitarías darle un perfil. Sin embargo, como ejemplo, en algún código crítico de tiempo que tuve que revisar, llamamos constantemente "nueva Fecha(). GetTime()" - reemplazando eso con "System.currentTimeMillis()" hizo una diferencia significativa porque no estábamos instantaneamente instanciando objetos Date. – Rich

+3

"será más lento" es bastante subjetivo. La manipulación de campo de calendario y fecha se trata principalmente de cambiar la representación subyacente "larga" de la fecha de todos modos, lo que significa que "más lento" se reduce a qué tan rápido es crear objetos, lo que es mucho más rápido de lo que la mayoría piensa. –

1

En primer lugar, yo diría que lo reemplazas con JodaTime. http://joda-time.sourceforge.net/ Es una biblioteca de tiempo muy agradable. Le recomendamos que consulte esta página para ver qué fácil es agregar días o semanas a un punto particular en el tiempo: http://joda-time.sourceforge.net/key_period.html No se puede hacer esto, dispositivo móvil con JVM incompatible. Gorrón.

Su primer ejemplo es más fácil de leer y será más fácil de usar por sus desarrolladores. También utiliza las clases de calendario, que es la forma generalmente aceptada para manipular las fechas en Java. Lo que lo hace mejor es que tiene un nombre de método claro que establece la expectativa de lo que hace.

Así que si refactoriza su sistema para usar consistentemente com.DaveJ.util.date.DateUtils.addDaysToDate (fecha de fecha final, int noOfDays) puede hacer lo que quiera dentro de ese método, ya sea Calendar o millis o Joda y sea consistente con su aplicación. ¡No olvides escribir algunas pruebas unitarias para ello!

+0

Otra respuesta menciona la velocidad. Si tiene esta lógica encapsulada en un método, en un lugar, será MUY fácil compararla y ajustarla según la velocidad que sea necesaria. – Freiheit

0

¡Depende! Debido a los segundos intercalares, horario de verano y otras rarezas de calendario, los dos no siempre son equivalentes.

Para uso comercial y diario, utilice siempre el primer método y el rendimiento no está nada mal. Manejará esas cosas por ti.

Para necesidades científicas, a menudo tiene que usar un reloj monótono (aquí el segundo).

0

Los dos métodos pueden dar resultados diferentes cuando se trata de un cambio en el horario de verano. Imagine que la hora actual es 23:50 y a las 02:00 el reloj salta a 03:00. Cuando acaba de agregar 7 días en milisegundos, el tiempo sería 00:50 al día siguiente. Complementos 7 días, el tiempo resultante seguiría siendo 23:50.

Para completar la confusión, también puedes probar add(Calendar.WEEK_OF_YEAR, 1), aunque no estoy seguro de cómo diferiría.

0

Dado que lo está usando en el dispositivo móvil, es preferible usar el primer método. La razón es que su código debe ser independiente de un calendario específico, horario de verano y otros problemas, como el exceso de segundos (segundos intercalares).

Tienes que eliminar la dependencia de GregorianCalendar y crearlo usando Calendar.getInstance().

+0

Realmente no debería usar 'getInstance()', en este caso. Supongo que el código está tratando de calcular 1 semana en el futuro de acuerdo con el calendario gregoriano, no una semana en el futuro de acuerdo con el calendario local del usuario. Aunque no sé por qué el usuario usaría el Calendario decimal de la Revolución Francesa. –

3

Tenga mucho cuidado con el uso del método dos que caught me out el otro día. Considere

private static long ONE_YEAR_AS_MILLISECONDS = 365*24*60*60*1000; 

Esto parece bastante inocente, pero en realidad no producirá lo que se espera que la multiplicación de números enteros que utiliza, cuando se multiplica por cada uno de los otros números enteros, provoca un desbordamiento numérico y dará lugar a un resultado inesperado. Esto se debe a que el valor máximo int en Java es 2.147.483.647 y, sin embargo, hay 31,536,000,000 ms en un año. En mi máquina, el código anterior produce 1.471.228.928, lo que obviamente no es correcto.

su lugar usted necesita para hacer esto:

private static long ONE_YEAR_AS_MILLISECONDS = 365L*24L*60L*60L*1000L; 
3

El más adelante se puede hacer en java 8, Java 8 rocas !!

public static void main(String[] args) { 
     LocalDate today = LocalDate.now(); 
     System.out.println("Current date: " + today); 

     //add 1 week to the current date 
     LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); 
     System.out.println("Next week: " + nextWeek); 
    } 
+0

Código más simple más corto que omite el 'ChronoUnit' con el mismo efecto:' today.plusWeeks (1) ' –

+0

Sugiero siempre pasar un huso horario (' ZoneId') al método 'now'. Si se omite la zona horaria predeterminada actual de su JVM se aplica implícitamente. ¡Ese valor predeterminado puede variar, incluso * durante * la ejecución de su aplicación! La zona horaria es crucial ya que en cualquier momento dado la fecha varía en todo el mundo. 'LocalDate.now (ZoneId.of (" America/Montreal "))' –

0

Para obtener un valor de fecha solamente, consulte the Answer by javaHelper. La clase LocalDate no tiene, a propósito, la hora del día ni la zona horaria.

ZonedDateTime

Para un valor de fecha y hora, utilice ZonedDateTime para representar una fecha y una hora del día junto con una zona de tiempo para dar cuenta de las anomalías tales como el horario de verano (DST).

ZoneId zoneId = ZoneId.of("America/Montreal"); 
ZonedDateTime now = ZonedDateTime.now(zoneId); 
ZonedDateTime weekLater = now.plusWeeks(1); 

O agregue un número arbitrario de días.

ZonedDateTime later = now.plusDays(someNumberOfDays); 

Sobre java.time

El marco java.time está incorporado en Java 8 y versiones posteriores. Estas clases suplantan a las antiguas clases problemáticas de fecha y hora como java.util.Date, .Calendar, & java.text.SimpleDateFormat. El proyecto Joda-Time, ahora en maintenance mode, recomienda la migración a java.time.

Para obtener más información, consulte el Oracle Tutorial. Y busque Stack Overflow para obtener muchos ejemplos y explicaciones.

Gran parte de la funcionalidad java.time está de vuelta-portado a Java 6 & 7 en ThreeTen-Backport y adaptado además para Android en ThreeTenABP.

El proyecto ThreeTen-Extra amplía java.time con clases adicionales. Este proyecto es un terreno de prueba para posibles adiciones futuras a java.time.

Cuestiones relacionadas