列出Android 4+中特定日期的事件(ALL_DAY问题)

33

我正在尝试在Android 4+中获取所选日期发生的所有事件。

据我了解,CalendarContract.Instances是最容易获取事件的方式,因为它处理重复事件和单次事件。

但是,我在处理时间戳时遇到了一些问题。具体地说,它似乎对ALL_DAY事件进行了不同的处理。

我从以下代码开始(start是我要获取事件的日期,毫秒级的计算是为了避免在第二天凌晨12点开始的不必要事件,Calendar使用默认时区)。

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

这段代码似乎针对许多边缘情况、不同的时区以及跨越多天的事件能够良好运作,但是却有一个例外:全天事件。

当我查看带有ALL_DAY标志的返回事件时:

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

我得到的结果是:EVENT(10075):2012年9月13日星期四02:00:00 CEST - 2012年9月15日星期六02:00:00 CEST

在我的看法中,query 希望以毫秒为单位提供基于时区的开始和结束时间,尽管 API 表明需要 UTC 时间戳。但是标记为 ALL_DAY 的事件使用基于 UTC 的毫秒数(因此我会因为+2时区而多得到2个小时)。

我还尝试计算并添加时区偏移量。然后整天的事件就可以正常工作了,但其他所有事件都不行。

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

虽然可以通过迭代游标、修改 ALL_DAY 事件并删除不必要的事件来轻松解决此问题,但我想知道是否有更好的方法。或者这是 Android 的 bug 吗?但是如果这是一个 bug,为什么系统日历功能正常?这种不一致的行为对我来说很奇怪。

谢谢。


你能提供一个手动操作的例子吗?我有点困惑。 - MobileMon
是的,谷歌的日历API似乎相当有问题...这个API中有很多相当幼稚和愚蠢的错误 :( - qkx
1
现在是2014年,这个错误似乎仍然存在... ALL_DAY事件使用时区而不是应该使用的UTC。请参阅此错误报告:https://code.google.com/p/android/issues/detail?id=14051 - Jose_GD
你解决了如何优雅地处理这个问题吗?否则我会在上面放置赏金!我也在苦苦挣扎着同样的问题。 - brandall
1个回答

1
Calendar API也与设备相关,你的代码在Android - 4.4.4 KitKat中可以正常工作,但在其他设备上可能会出现问题。我已测试以下代码,在我测试的所有设备上均可正常工作。

请尝试这样做:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接