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.

  • Almacenamiento de moneda en la base de datos SQlite android
  • Vista de accesorios (similar a inputAccessoryView para iOS) para el teclado Android
  • Problemas de repetición de AudioTrack de Android en MODE_STATIC
  • Android NDK: load_library: no se puede localizar srand
  • AChartEngine Y-Axis personaliza los márgenes de área de etiquetas y los valores de gráfico como String?
  • Android cómo detener la actualización Fragmentos en el cambio de ficha
  • Proceso para comprimir una imagen para subirla a un servidor en Android
  • GamesClient no se conecta. Error: "Llamar a connect () y esperar a que onConnected () sea llamado."
  • Declaración de la capacidad de una lista en Java
  • Obtener un inflador de diseño desde el ApplicationContext
  • Android, no puede obtener methed setOnLongClickListener para trabajar
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.