List events for specific day in Android 4+ (ALL_DAY issue)
Asked Answered
A

1

33

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.

Afterbirth answered 5/10, 2012 at 18:17 Comment(5)
Can you post an example of how you manually do this??? I'm confusedNeysa
yeah, google's calendar api seems pretty buggy...there are lot of quite childhood and stupid bugs in this api :(Brumbaugh
It's 2014 and the bug seems to persist... ALL_DAY events use the timezone and not UTC as they should. See this bug report: code.google.com/p/android/issues/detail?id=14051Duality
Did you ever resolve how to handle this gracefully? I'm going to stick a bounty on it otherwise! Struggling with exactly the same issue.Marshamarshal
Similar question from me and I put a bounty on it: #27516898. A hack that seems to work, though, is to set your formatter to UTC when displaying an all_day event. E.g. if (isAllDay) formatter.setTimeZone (TimeZone.getTimeZone ("UTC"));Himyaritic
S
1

Calendar api is also a some what device dependent, your code is working perfectly in Android - 4.4.4 KitKat but not in other devices. The following code is working perfectly all devices in which i have tested.

Try this:

public Cursor fetchCursor(Calendar start) {
    Calendar end = (Calendar) start.clone();
    end.add(Calendar.DATE, 1);
    ContentResolver resolver = this.getContentResolver();
    return CalendarContract.Instances.query(resolver,  new String[] { "calendar_id", "title", "description",
                "dtstart", "dtend", "eventLocation" }, start.getTimeInMillis(),
                end.getTimeInMillis());
}
Sharma answered 29/9, 2014 at 6:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.