Android Java – Joda La fecha es lenta

Uso de Joda 1.6.2 con Android

El código siguiente se bloquea durante unos 15 segundos.

DateTime dt = new DateTime(); 

Originalmente publicado este post Android Java – Joda Fecha es lento en Eclipse / Emulador –

Acabo de probarlo de nuevo y su todavía no es mejor. ¿Alguien más tiene este problema o sabe cómo solucionarlo?

También me encontré con este problema. Las sospechas de Jon Skeet eran correctas, el problema es que las zonas horarias se están cargando de manera muy ineficaz, abriendo un archivo jar y luego leyendo el manifiesto para tratar de obtener esta información.

Sin embargo, simplemente llamar a DateTimeZone.setProvider([custom provider instance ...]) no es suficiente porque, por razones que no tienen sentido para mí, DateTimeZone tiene un inicializador estático donde llama a getDefaultProvider() .

Para estar completamente seguro, puede anular este valor predeterminado configurando esta propiedad del sistema antes de llamar a cualquier cosa en el joda.

En su actividad, por ejemplo, añada esto:

 @Override public void onCreate(Bundle savedInstanceState) { System.setProperty("org.joda.time.DateTimeZone.Provider", "com.your.package.FastDateTimeZoneProvider"); } 

Entonces todo lo que tienes que hacer es definir FastDateTimeZoneProvider . Escribí lo siguiente:

 package com.your.package; public class FastDateTimeZoneProvider implements Provider { public static final Set<String> AVAILABLE_IDS = new HashSet<String>(); static { AVAILABLE_IDS.addAll(Arrays.asList(TimeZone.getAvailableIDs())); } public DateTimeZone getZone(String id) { if (id == null) { return DateTimeZone.UTC; } TimeZone tz = TimeZone.getTimeZone(id); if (tz == null) { return DateTimeZone.UTC; } int rawOffset = tz.getRawOffset(); //sub-optimal. could be improved to only create a new Date every few minutes if (tz.inDaylightTime(new Date())) { rawOffset += tz.getDSTSavings(); } return DateTimeZone.forOffsetMillis(rawOffset); } public Set getAvailableIDs() { return AVAILABLE_IDS; } } 

He probado esto y parece que funciona en Android SDK 2.1 + con joda versión 1.6.2. Por supuesto, se puede optimizar aún más, pero mientras perfilaba mi aplicación ( mogwee ), esto disminuyó el tiempo de inicialización de DateTimeZone de ~ 500ms a ~ 18ms.

Si está usando proguard para crear su aplicación, tendrá que agregar esta línea a proguard.cfg porque Joda espera que el nombre de la clase sea exactamente como usted especifica:

 -keep class com.your.package.FastDateTimeZoneProvider 

Creo firmemente que es porque tiene que construir la cronología ISO para la zona horaria por defecto, lo que probablemente implica la lectura de toda la información de zona horaria en.

Puede verificar esto llamando ISOChronology.getInstance() primera vez que, y luego el tiempo de una llamada posterior a new DateTime() . Sospecho que será rápido.

¿Sabe qué zonas horarias van a ser relevantes en su aplicación? Usted puede encontrar que puede hacer todo el asunto mucho más rápido reconstruyendo Joda Time con una base de datos de zona de tiempo muy reducido. Como alternativa, llame a DateTimeZone.setProvider() con su propia implementación de Provider que no hace tanto trabajo.

Vale la pena comprobar si en realidad es el problema primero, por supuesto 🙂 También puede intentar pasar explícitamente en la zona horaria UTC, que no requerirá la lectura en la base de datos de zona horaria … aunque nunca se sabe cuándo Activar accidentalmente una llamada que requiere la zona horaria predeterminada, momento en el que incurrirá en el mismo coste.

Sólo necesito UTC en mi aplicación. Así que, siguiendo el consejo de unchek, usé

 System.setProperty("org.joda.time.DateTimeZone.Provider", "org.joda.time.tz.UTCProvider"); 

org.joda.time.tz.UTCProvider es realmente utilizado por JodaTime como la copia de seguridad secundaria, así que pensé ¿por qué no usarlo para uso principal? Hasta aquí todo bien. Se carga rápido.

La respuesta superior proporcionada por plowman no es confiable si debe tener cálculos horarios precisos para sus fechas. Aquí hay un ejemplo de problema que puede ocurrir:

Supongamos que su objeto DateTime está configurado para las 4:00 am, una hora después de que los ahorros de luz diurna hayan comenzado ese día. Cuando Joda comprueba el proveedor de FastDateTimeZoneProvider antes de las 3:00 am (es decir, antes de los ahorros de luz) obtendrá un objeto DateTimeZone con el desplazamiento incorrecto porque la tz.inDaylightTime(new Date()) devolverá false.

Mi solución fue adoptar la recientemente publicada joda-time-android library . Utiliza el núcleo de Joda, pero se asegura de cargar una zona horaria sólo según sea necesario desde la carpeta en bruto. La configuración es fácil con gradle. En su proyecto, extienda la clase Application y añada lo siguiente en su onCreate() :

 public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); JodaTimeAndroid.init(this); } } 

El autor escribió un artículo sobre el blog el año pasado.

Puedo confirmar este problema con la versión 1, 1.5 y 1.62 de joda. Date4J está funcionando bien para mí como una alternativa.

http://www.date4j.net/

Acabo de realizar la prueba que @ "Name is carl" publicado, en varios dispositivos. Debo señalar que la prueba no es completamente válida y los resultados son engañosos (en que sólo refleja una sola instancia de DateTime).

  1. De su prueba, Cuando se compara DateTime con Date, DateTime se ve obligado a analizar el String ts, donde Date no analiza nada.

  2. Mientras que la creación inicial del DateTime era exacta, toma SOLAMENTE ese mucho tiempo en la PRIMERA creación … cada ejemplo después de que era 0ms (o muy cerca de 0ms)

Para comprobar esto, utilicé el código siguiente y creé 1000 nuevas instancias de DateTime en un dispositivo Android 2.3

  int iterations = 1000; long totalTime = 0; // Test Joda Date for (int i = 0; i < iterations; i++) { long d1 = System.currentTimeMillis(); DateTime d = new DateTime(); long d2 = System.currentTimeMillis(); long duration = (d2 - d1); totalTime += duration; log.i(TAG, "datetime : " + duration); } log.i(TAG, "Average datetime : " + ((double) totalTime/ (double) iterations)); 

Mis resultados mostraron:

 Datetime: 264
 Datetime: 0
 Datetime: 0
 Datetime: 0
 Datetime: 0
 Datetime: 0
 Datetime: 0
 ...
 Datetime: 0
 Datetime: 0
 Datetime: 1
 Datetime: 0
 ...
 Datetime: 0
 Datetime: 0
 Datetime: 0

Por lo tanto, el resultado fue que la primera instancia fue 264ms y más del 95% de los siguientes fueron 0ms (ocasionalmente tenía un 1 ms, pero nunca tuvo un valor mayor que 1ms).

Espero que esto da una imagen más clara del costo de usar Joda.

NOTA: Estaba usando joda-time versión 2.1

Encontré solución para mí. Cargo UTC y la zona horaria por defecto. Así que es muy rápido. Y creo que en este caso necesito capturar broadcast TIME ZONE CHANGE y recargar la zona horaria por defecto.

 public class FastDateTimeZoneProvider implements Provider { public static final Set<String> AVAILABLE_IDS = new HashSet<String>(); static { AVAILABLE_IDS.add("UTC"); AVAILABLE_IDS.add(TimeZone.getDefault().getID()); } public DateTimeZone getZone(String id) { int rawOffset = 0; if (id == null) { return DateTimeZone.getDefault(); } TimeZone tz = TimeZone.getTimeZone(id); if (tz == null) { return DateTimeZone.getDefault(); } rawOffset = tz.getRawOffset(); //sub-optimal. could be improved to only create a new Date every few minutes if (tz.inDaylightTime(new Date())) { rawOffset += tz.getDSTSavings(); } return DateTimeZone.forOffsetMillis(rawOffset); } public Set getAvailableIDs() { return AVAILABLE_IDS; } } 

Usando dlew / joda-tiempo-androide gradle dependencia que sólo toma 22,82 ms (milisegundos). Así que te recomiendo que lo uses en lugar de anular nada.

Esta nota rápida para completar la respuesta sobre date4j de @Steven

Corrí un punto de referencia rápido y sucio comparando java.util.Date , jodatime y date4j en el dispositivo Android más débil que tengo (HTC Dream / Sapphire 2.3.5).

Detalles: normal build (no proguard), implementando el FastDateTimeZoneProvider para jodatime.

Aquí está el código:

 String ts = "2010-01-19T23:59:59.123456789"; long d1 = System.currentTimeMillis(); DateTime d = new DateTime(ts); long d2 = System.currentTimeMillis(); System.err.println("datetime : " + dateUtils.durationtoString(d2 - d1)); d1 = System.currentTimeMillis(); Date dd = new Date(); d2 = System.currentTimeMillis(); System.err.println("date : " + dateUtils.durationtoString(d2 - d1)); d1 = System.currentTimeMillis(); hirondelle.date4j.DateTime ddd = new hirondelle.date4j.DateTime(ts); d2 = System.currentTimeMillis(); System.err.println("date4j : " + dateUtils.durationtoString(d2 - d1)); 

Aquí están los resultados :

  debug | normal joda : 3s (3577ms) | 0s (284ms) date : 0s (0) | 0s (0s) date4j : 0s (55ms) | 0s (2ms) 

Una última cosa, los tamaños jar:

 jodatime 2.1 : 558 kb date4j : 35 kb 

Creo que voy a dar date4j un intento.

  • Serializar objeto personalizado que contiene objetos JodaTime en JSON
  • ¿Cómo manejar las diferencias de la base de datos de horarios de JodaTime y Android?
  • En Java, cómo obtener cadenas de días de la semana (Sun, Mon, ..., Sat) con el sistema de configuración por defecto (idioma)
  • ¿Cómo clonar Joda DateTime?
  • Intervalo de tiempo límite en el selector de tiempo
  • Anular el primer día de la semana en joda?
  • Uso de ORM de azúcar con UUID o Joda-Time
  • joda tiempo consumir demasiada memoria
  • Encuentre el día y la hora restante usando jodatime
  • Cómo escribir y leer org.joda.time.Date en la clase Parcelable
  • Adición de Joda Time a Android Studio
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.