I want to extend a discussion I started on the Reddit Android Dev community yesterday with a new question: How do you manage an up-to-date timezone database shipped with your app using the JodaTime library on a device that has outdated timezone information?
The problem
The specific issue at hand relates to a particular timezone, "Europe/Kaliningrad". And I can reproduce the problem: On an Android 4.4 device, if I manually set its time zone to the above, calling new DateTime()
will set this DateTime
instance to a time one hour before the actual time displayed on the phone's status bar.
I created a sample Activity
to illustrate the problem. On its onCreate()
I call the following:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ResourceZoneInfoProvider.init(getApplicationContext());
ViewGroup v = (ViewGroup) findViewById(R.id.root);
addTimeZoneInfo("America/New_York", v);
addTimeZoneInfo("Europe/Paris", v);
addTimeZoneInfo("Europe/Kaliningrad", v);
}
private void addTimeZoneInfo(String id, ViewGroup root) {
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.setTimeZone(id);
//Joda does not update its time zone automatically when there is a system change
DateTimeZone.setDefault(DateTimeZone.forID(id));
View v = getLayoutInflater().inflate(R.layout.info, root, false);
TextView idInfo = (TextView) v.findViewById(R.id.id);
idInfo.setText(id);
TextView timezone = (TextView) v.findViewById(android.R.id.text1);
timezone.setText("Time zone: " + TimeZone.getDefault().getDisplayName());
TextView jodaTime = (TextView) v.findViewById(android.R.id.text2);
//Using the same pattern as Date()
jodaTime.setText("Time now (Joda): " + new DateTime().toString("EEE MMM dd HH:mm:ss zzz yyyy"));
TextView javaTime = (TextView) v.findViewById(R.id.time_java);
javaTime.setText("Time now (Java): " + new Date().toString());
root.addView(v);
}
ResourceZoneInfoProvider.init()
is part of the joda-time-android library and it is meant to initialize Joda's time zone database. addTimeZoneInfo
overwrites the device's time zone and inflates a new view where the updated time zone information is displayed. Here is an example of result:
Note how for "Kaliningrad", Android maps it to "GMT+3:00" because that was the case until 26 October 2014 (see Wikipedia article). Even some web sites still show this time zone as GMT+3:00 because of how relatively recent this change is. The correct, however, is "GMT+2:00" as displayed by JodaTime.
Flawed possible solutions?
This is a problem because no matter how I try to circumvent it, in the end, I have to format the time to display it to the user in their time zone. And when I do that using JodaTime, the time will be incorrectly formatted because it will mismatch the expected time the system is displaying.
Alternatively, suppose I handle everything in UTC. When the user is adding an event in the calendar and picks a time for the reminder, I can set it to UTC, store it in the db like that and be done with it.
However, I need to set that reminder with Android's AlarmManager
not at the UTC time I converted the time set by the user but at the one relative to the time they want the reminder to trigger. This requires the time zone info to come into play.
For example, if the user is somewhere at UTC+1:00 and he or she sets a reminder for 9:00am, I can:
- Create a new
DateTime
instance set for 09:00am at the user's timezone and store its milliseconds in the db. I can also directly use the same milliseconds with theAlarmManager
; - Create a new
DateTime
instance set for 09:00am at UTC and store its milliseconds in the db. This better addresses a few other issues not exactly related to this question. But when setting the time with theAlarmManager
, I need to compute its millisecond value for 09:00am at the user's timezone; - Ignore completely Joda
DateTime
and handle the setting of the reminder using Java'sCalendar
. This will make my app rely on outdated time zone information when displaying the time but at least there won't be inconsistencies when scheduling with theAlarmManager
or displaying the dates and times.
What am I missing?
I may be over thinking this and I'm afraid I might be missing something obvious. Am I? Is there any way I could keep using JodaTime on Android short of adding my own time zone management to the app and completely disregard all built-in Android formatting functions?