I'm attempting to get all events happening on selected day in Android 4+.
As far as I understand, CalendarContract.Instances is the easiest way of getting events, since it handles both recurring events and single time events.
However, I have some problems with its way of handling timestamps. To be specific, it seems to treat ALL_DAY events differently.
I've started with the following code (start
is the day for which I'm fetching events, millisecond "maths" is to avoid unnecessary events beginning on the 12 am of the next day, Calendar uses default timezone).
public Cursor fetchCursor(Calendar start) {
Calendar end = (Calendar) start.clone();
end.add(Calendar.DATE, 1);
long startTime = start.getTimeInMillis() + 1;
long endTime = end.getTimeInMillis() - 1;
ContentResolver resolver = mContext.getContentResolver();
return CalendarContract.Instances.query(resolver, projection, startTime, endTime);
}
This code seems to work well with many edge cases, different timezones, events that span multiple days... everything except all day events.
When I examined returned event with ALL_DAY flag:
Cursor c = fetchCursor(date);
Log.e("SIZE", String.valueOf(c.getCount()));
while (c.moveToNext()) {
long begin = c.getLong(2); // CalendarContract.Instances.BEGIN
long end = c.getLong(3); // CalendarContract.Instances.END
Date beginDate = new Date(begin);
Date endDate = new Date(end);
Log.e("EVENT", String.valueOf(begin) + " - " + String.valueOf(end));
Log.e("EVENT", beginDate.toString() + " - " + endDate.toString());
}
I got: EVENT(10075): Thu Sep 13 02:00:00 CEST 2012 - Sat Sep 15 02:00:00 CEST 2012
.
For me it looks like query
expects range begin and end in millis since epoch in MY TIMEZONE (yet API states it needs UTC based timestamp). But events marked as ALL_DAY use millis since epoch in UTC (so I get 2 additional hours because of +2 timezone).
I also tried calculating and adding timezone offset. Then all day events worked fine but everything else... not.
private long getTimezoneOffset(TimeZone zone, long date) {
long delta = zone.getOffset(date);
return delta;
}
private long getTimeInUTC(Calendar date) {
long time = date.getTimeInMillis();
time += getTimezoneOffset(date.getTimeZone(), time);
return time;
}
public Cursor fetchCursor(Calendar start) {
Calendar end = (Calendar) start.clone();
end.add(Calendar.DATE, 1);
long startTime = getTimeInUTC(start) + 1;
long endTime = getTimeInUTC(end) - 1;
ContentResolver resolver = mContext.getContentResolver();
return CalendarContract.Instances.query(resolver, projection, startTime, endTime);
}
While there is quite easy way to fix this issue by iterating over cursor, altering ALL_DAY events and removing unnecessary events, I would like to know if there is a better way. Or maybe this is Android bug? But if it is a bug then why System Calendar works OK? This inconsistent behavior seems odd to me.
Thanks.