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.
- Cómo actualizar fragmento anterior después de cerrar una actividad que se inició dentro de un adaptador?
- ¿Cómo evito que Android Studio colapse automáticamente mis paquetes en la navegación de proyectos?
- Reutilización de tareas asíncronas de Android
- ¿Por qué Locale.getDefault (). GetLanguage () en Android devuelve el nombre para mostrar en lugar del código de idioma?
- Android: compás + distancia en una vista de lista
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.
- Google Map v2 MapFragment es extremadamente laggy al volver de la backstack
- Generar un Javadoc para mi proyecto de Android
- Cómo crear un archivo de encabezado C utilizando la herramienta Javah
- ¿Cómo leer un archivo AndroidManifest.xml (en binario)?
- ¿Dónde se puede encontrar AndroidObservable.fromBroadcast ahora?
- Androide. Iniciar aplicación desde Dialer
- Adición de un método de convieniencia a una clase existente (excepción de generación de clase)
- ¿Cómo inserto caracteres especiales como texto en el editor de XML para 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
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.
- ¿Qué es exactamente el parámetro "label" en ClipData en Android?
- Cómo contestar una llamada mediante programación