2010-12-17 10 views
7

No estoy seguro de lo que estoy haciendo mal, pero tengo una pieza de código que calcula el número de días entre dos fechas, y que será similar a la siguiente:Error en el calendario/fecha de Java para el 2 de octubre de 2010?

final Calendar first = new GregorianCalendar(2010, Calendar.OCTOBER, 1); 
final Calendar last = new GregorianCalendar(2010, Calendar.NOVEMBER, 1); 

final long difference = last.getTimeInMillis() - first.getTimeInMillis(); 
final long days = difference/(1000 * 60 * 60 * 24); 

System.out.println("difference: " + difference); 
System.out.println("days: " + days); 

Para resumir , el bloque de código anterior calcula el número de días entre el 1 de octubre de 2010 y el 1 de noviembre de 2010. estoy esperando para ver lo devolverá 31 días (ya que hay 31 días en octubre)

difference: xxxx 
days: 31 

sino que está mostrando 30 días en octubre!

difference: 2674800000 
days: 30 

he logrado reducirlo a entre el 2 las fechas octubre de 2010 y 3 de octubre de 2010, que sólo parece haber 82800000 milisegundos, en lugar de un total de 86400000 milisegundos (exactamente una hora que faltan).

¿Alguien tiene alguna idea de lo que estoy haciendo mal? ¿O es el 2 de octubre una fecha especial que tiene un minuto menos que un día normal?

+5

edite el código para reemplazar 9 y 10 con las constantes de mes. Esto sigue confundiendo a la gente aquí. – Thilo

+0

Ah, sí, sí, aclamaciones, creo que alguien ya lo editó – jklp

Respuesta

9

(86400000 - 82800000)/1000 = 3600, que es una hora. Está viendo el horario de ahorro de luz diurna, combinado con el redondeo de enteros matemáticos

Puede solucionarlo haciendo cálculos con números flotantes y redondeando al final, o puede consultar una biblioteca como Joda time que ofrece mucho mejor fecha matemática que la incorporada.

+0

Según http://www.timeanddate.com /time/dst/2010b.html el 2 de octubre es el día cambiante en partes de Australia. –

-3

El código que coloca en su publicación es calcular el tiempo entre el 1 de septiembre y el 1 de octubre, no el 1 de octubre y el 1 de noviembre. El resultado es correcto para el código que publicó.

+3

El valor del mes está basado en 0. por ejemplo, 0 para enero. –

+0

http://download.oracle.com/javase/6/docs/api/java/util/GregorianCalendar.html#GregorianCalendar%28int,%20int,%20int%29 –

0

Puede ser mejor comparar el año y el día o el año en lugar de los milisegundos que pasan en un día.

int lastYear= last.get(Calendar.YEAR); 
int firstYear= first.get(Calendar.YEAR); 
int lastDayofYear = last.get(Calendar.DAY_OF_YEAR); 
int firstDayofYear = first.get(Calendar.DAY_OF_YEAR); 
int nDaysElapse = lastDayofYear - firstDayofYear; 
int nYearsElapse = lastYear- firstYear; 
int days = (nYearsElapse*365)+nDaysElapse; 
0

Debe leer this post para obtener una mejor comprensión de cómo calendario está interrelacionado con los sellos de fecha/hora.

Después de leer ese sitio, mis preguntas iniciales fueron:

¿Qué quiere decir por día? ¿Te refieres a 'bloques de 24 horas' o quieres decir días calendario? En el mismo sentido, ¿te importa si estás un poco apagado debido a los ahorros de luz diurna, etc.?

Si se refiere a días del calendario, lo mejor es, probablemente, a:

final Calendar first = new GregorianCalendar(2010, 9, 1); 
final Calendar last = new GregorianCalendar(2010, 10, 1); 

Calendar difference = Calendar.getInstance(); 
difference.setTimeInMillis(last.getTimeInMillis() - first.getTimeInMillis()); 

int numDays = difference.get(Calendar.DAY_OF_YEAR) - difference.getMinimum(Calendar.DAY_OF_YEAR); 

Por supuesto, el código anterior sólo funcionará si el número de días < 365. Usted tendrá que crear un cálculo de rodadura, por ejemplo

int yearDiff = last.get(Calendar.YEAR) - first.get(Calendar.YEAR); 
Calendar tmp = new GregorianCalendar(); 
tmp.setTimeInMillis(first.getTimeInMillis()); 
for(int i = 0; i < yearDiff; i++) { 
    numDays += tmp.getActualMaximum(Calendar.DAY_OF_YEAR); 
    i++; 
    tmp.add(Calendar.YEAR, 1); 
} 

Esto debería permitir obtener el número de días de una manera correcta y coherente, sin preocuparse de Horario de Verano, los años bisiestos etc.

Dicho esto, JodaTime probablemente tiene esta funcionalidad incorporada.

0

El answer by Brad Mace es correcto.

utilizar una biblioteca

Esta pregunta es un buen ejemplo de por qué se debe utilizar una buena marchitan biblioteca en tiempo de la fecha de liar. Para Java que significa el uso de ya sea Joda-Time o el nuevo paquete java.time en Java 8.

Joda-Time

Ejemplo código en Joda-Time.

DateTimeZone timeZone = DateTimeZone.forID("Australia/Melbourne"); 
DateTime theFirst = new DateTime(2014, DateTimeConstants.OCTOBER, 1, 0, 0, 0, timeZone).withTimeAtStartOfDay(); 
DateTime nextMonth = theFirst.plusMonths(1).withTimeAtStartOfDay(); 
int days = Days.daysBetween(theFirst, nextMonth).getDays(); 

O si no se preocupan por la hora del día, utilizar la clase LocalDate.

java.time

Java 8 y posterior viene con un nuevo marco java.time suplantar las antiguas clases java.util.Date/.Calendar. Inspirado por Joda-Time, definido por JSR 310, y extendido por el proyecto ThreeTen-Extra.

Código de ejemplo con Java 8. Tenga en cuenta que la enumeración ChronoUnit devuelve un long de 64 bits en lugar de int.

LocalDate firstOfOctober = LocalDate.of(2010 , java.time.Month.OCTOBER , 1); 
LocalDate nextMonth = firstOfOctober.plusMonths(1); 
long daysInMonth = ChronoUnit.DAYS.between(firstOfOctober , nextMonth); 
Cuestiones relacionadas