Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Java - Joda Date is slow

Using Joda 1.6.2 with Android

The following code hangs for about 15 seconds.

DateTime dt = new DateTime(); 

Originally posted this post Android Java - Joda Date is slow in Eclipse/Emulator -

Just tried it again and its still not any better. Does anyone else have this problem or know how to fix it?

like image 568
Mark Worsnop Avatar asked Feb 20 '11 20:02

Mark Worsnop


2 Answers

I also ran into this problem. Jon Skeet's suspicions were correct, the problem is that the time zones are being loaded really inefficiently, opening a jar file and then reading the manifest to try to get this information.

However, simply calling DateTimeZone.setProvider([custom provider instance ...]) is not sufficient because, for reasons that don't make sense to me, DateTimeZone has a static initializer where it calls getDefaultProvider().

To be completely safe, you can override this default by setting this system property before you ever call anything in the joda.

In your activity, for example, add this:

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

Then all you have to do is define FastDateTimeZoneProvider. I wrote the following:

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;     } } 

I've tested this and it appears to work on Android SDK 2.1+ with joda version 1.6.2. It can of course be optimized further, but while profiling my app (mogwee), this decreased the DateTimeZone initialize time from ~500ms to ~18ms.

If you are using proguard to build your app, you'll have to add this line to proguard.cfg because Joda expects the class name to be exactly as you specify:

-keep class com.your.package.FastDateTimeZoneProvider 
like image 52
plowman Avatar answered Oct 26 '22 18:10

plowman


I strongly suspect it's because it's having to build the ISO chronology for the default time zone, which probably involves reading all the time zone information in.

You could verify this by calling ISOChronology.getInstance() first - time that, and then time a subsequent call to new DateTime(). I suspect it'll be fast.

Do you know which time zones are going to be relevant in your application? You may find you can make the whole thing much quicker by rebuilding Joda Time with a very much reduced time zone database. Alternatively, call DateTimeZone.setProvider() with your own implementation of Provider which doesn't do as much work.

It's worth checking whether that's actually the problem first, of course :) You may also want to try explicitly passing in the UTC time zone, which won't require reading in the time zone database... although you never know when you'll accidentally trigger a call which does require the default time zone, at which point you'll incur the same cost.

like image 39
Jon Skeet Avatar answered Oct 26 '22 18:10

Jon Skeet