Comportamiento diferente de la clase Calendar en Java y Android

Estaba trabajando en recuperar la fecha de la primera semana del año y encontré un comportamiento muy extraño.

He probado el siguiente fragmento de código tanto en la aplicación de consola de Java y emulador de Android y produce diferentes resultados.

Calendar cal = Calendar.getInstance(); cal.set(Calendar.WEEK_OF_YEAR, 1); cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); System.out.println(sdf.format(cal.getTime())); 

La siguiente producción fue producida

Android log cat: 2012/09/17 (incorrecto)

Consola Java: 2012/01/01 (correcto)

Y lo extraño es que si usé código siguiente en Android y Java produce la misma salida correcta. La única diferencia fue que intercambié la 2ª y 3ª línea del código anterior.

  Calendar cal = Calendar.getInstance(); cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); cal.set(Calendar.WEEK_OF_YEAR, 1); System.out.println(sdf.format(cal.getTime())); 

Android log cat: 2012/01/01 (correcto)

Consola Java: 2012/01/01 (correcto)

Soy muy curioso saber sobre esto.

Gracias por adelantado.

One Solution collect form web for “Comportamiento diferente de la clase Calendar en Java y Android”

Parece que la clase Calendar tiene internamente dos contenedores de datos.

protected long time

protected int[] fields

Por lo tanto, cuando llama a cal.set(Calendar.WEEK_OF_YEAR, 1) , cambia los valores en los fields , no el time de la clase.

En Java API

Protected abstract void computeFields ()

Convierte el valor de tiempo actual de milisegundos en valores de campo de calendario en campos []. Esto le permite sincronizar los valores del campo de calendario con una nueva hora que se establece para el calendario. El tiempo no es recalculado primero; Para recalcular el tiempo, luego los campos, llame al método complete ().

Creo que en el primer caso de Android computeFields() no se llama internamente.

Para comprobar mi teoría, probé el código siguiente:

 SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd"); Calendar cal = Calendar.getInstance(); System.out.println(cal); System.out.println(sdf.format(cal.getTime())); cal.set(Calendar.WEEK_OF_YEAR, 1); System.out.println(cal); System.out.println(sdf.format(cal.getTime())); cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); System.out.println(cal); System.out.println(sdf.format(cal.getTime())); 

LogCat:

Java.util.GregorianCalendar [ time = 1348010308802, areFieldsSet = true , lenient = true, zone = org.apache.harmony.luni.internal.util.ZoneInfo ["null", mRawOffset = 0, mUseDst = false], firstDayOfWeek = 1 , DAY_OF_YEAR == 26, DAY_OF_YEAR == 262, DAY_OF_WEEK == 3 , DAY_OF_WEEK_IN_MONTH == 3, DAY_OF_YOUR == 3 , DAY_OF_WEEK_IN_MONTH == 3, AM_PM == 1, HOUR == 11, HOUR_OF_DAY = 23, MINUTE == 18, SECOND == 28, MILLISECOND == 802, ZONE_OFFSET == 0, DST_OFFSET == 0]

2012.09.18

Java.util.GregorianCalendar [ time = ?, areFieldsSet = false , lenient = true, zone = org.apache.harmony.luni.internal.util.ZoneInfo ["null", mRawOffset = 0, mUseDst = false], firstDayOfWeek = 1 , DAY_OF_YEAR == 26, DAY_OF_YEAR == 262, DAY_OF_WEEK == 3 , DAY_OF_WEEK_IN_MONTH == 3, DAY_OF_MONTH == 3 , DAY_OF_WEK == 3, DAY_OF_WEEK_IN_MONTH == 3, AM_PM == 1, HOUR == 11, HOUR_OF_DAY = 23, MINUTE == 18, SECOND == 28, MILLISECOND == 802, ZONE_OFFSET == 0, DST_OFFSET == 0]

2012.01.03

Java.util.GregorianCalendar [ time = ?, areFieldsSet = false , lenient = true, zone = org.apache.harmony.luni.internal.util.ZoneInfo ["null", mRawOffset = 0, mUseDst = false], firstDayOfWeek = 1 , DAY_OF_YEAR == 26, DAY_OF_YEAR == 262, DAY_OF_WEEK == 1 , DAY_OF_WEEK_IN_MONTH == 3, DAY_OF_MONTH == 4, DAY_OF_MONTH == 18, DAY_OF_YEAR == 1 , DAY_OF_WEEK_IN_MONTH == 3, AM_PM == 1, HOUR == 11, HOUR_OF_DAY = 23, MINUTE == 18, SECOND == 28, MILLISECOND == 802, ZONE_OFFSET == 0, DST_OFFSET == 0]

2012.09.16

Como podemos ver arriba, los valores en los campos se cambian, pero el tiempo interno se denomina ? , Diciendo que la time no se sincroniza con los fields .

Tienes un time sincronizar usando el método getTime() y lo imprimiste.

Creo que Calendar en Android está diseñado para retrasar la sincronización hasta que sea realmente necesario.

ADICIONAL

He encontrado lo siguiente en Java API:

Los campos del calendario se pueden cambiar usando tres métodos: set (), add (), y roll ().

Set (f, value) cambia el campo f a value. Además, establece una variable de miembro interna para indicar que se ha cambiado el campo f. Aunque el campo f cambia inmediatamente, los milisegundos del calendario no se vuelven a calcular hasta que se realice la siguiente llamada a get (), getTime () o getTimeInMillis () . Por lo tanto, varias llamadas a set () no activan múltiples cálculos innecesarios. Como resultado de cambiar un campo usando set (), otros campos también pueden cambiar, dependiendo del campo, el valor del campo y el sistema de calendario. Además, get (f) no necesariamente devolverá el valor después de que los campos hayan sido recalculados. Las especificaciones son determinadas por la clase concreta del calendario.

ADICIONAL

Para comprobar si "Los detalles están determinados por la clase de calendario concreta" es cierto, comprobé los códigos reales de Dalvik y JDK 6.

Set method in Calendario de Dalvik

Desde https://www.codeaurora.org/git/projects/qrd-gb-dsds-7225/repository/revisions/cc99b832a941dc8cbb86f1607d04eb87935ddbfd/entry/android/dalvik/libcore/luni/src/main/java/java/util/Calendar .Java

 public void set(int field, int value) { fields[field] = value; isSet[field] = true; areFieldsSet = isTimeSet = false; if (field > MONTH && field < AM_PM) { lastDateFieldSet = field; } if (field == HOUR || field == HOUR_OF_DAY) { lastTimeFieldSet = field; } if (field == AM_PM) { lastTimeFieldSet = HOUR; } } 

Método Set en el Calendario de JDK 6

 public void set(int field, int value) { if (isLenient() && areFieldsSet && !areAllFieldsSet) { computeFields(); } internalSet(field, value); isTimeSet = false; areFieldsSet = false; isSet[field] = true; stamp[field] = nextStamp++; if (nextStamp == Integer.MAX_VALUE) { adjustStamp(); } } 

Las implementaciones específicas son bastante diferentes. Para averiguar la razón exacta de su problema, debe examinar ambas implementaciones en detalle.

  • Cómo poner en cola los datos para el envío del servidor en android
  • Cómo solucionar el error de registro de Google Cloud Messaging: SERVICE_NOT_AVAILABLE?
  • Cambiar el color de la barra de navegación, Android
  • Reemplazar e incrementar el número en el nombre de archivo en una aplicación de Android
  • ¿Son los programas escritos en Java para Android más lento que el equivalente escrito en C incluido en Objective-C para iOS?
  • Uso de ProGuard con Android
  • Mensajes androide logcat invisibles en eclipse
  • Diseño de fragmentos: ¿Cómo adaptarse a múltiples diseños de pantalla mostrando / ocultando fragmentos dentro de una sola actividad?
  • No puedo cargar ningún proyecto después de actualizar Android Studio a v2.3
  • Intellij 13 Auto doc pop-up en la solución mouseover ya no funciona
  • Admob en fragmentos
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.