6

I'm using CalendarContract.Instances to get a set of calendar events. In general my queries work fine. However, the begin and end times for events in the "holidays" calendar come back in a wrong time zone. Events in one of my personal calendars come with correct times.

For example:

New Year's day "begins" at 04:00 PM, 31 Dec 2014.

where as

Opera "begins" at 02:00 PM, 11 Jan 2015.

I'm using exactly the same code to display both:

  SimpleDateFormat formatter = new SimpleDateFormat ("hh:mm a, d MMM yyyy", Locale.US);
  logD (prefix + i + ": " + formatter.format (data.startTime) + "; " + data.note);

where data.startTime maps to Instances.BEGIN and data.note maps to Instances.TITLE. The Opera is showing at the correct time, New Year's day is obviously 8 hours off (I'm in the US Pacific time zone).

If I view these in the Android calendar app, both show with the correct time.

Obviously, I can look at which calendar the event comes from and set the time zone accordingly to make it show with the correct time. However, I'm hoping there's a more proper solution that I'm unaware of.

Here's a snip of code that gets the event values from the cursor:

@Override
public View getView (int position, View convertView, ViewGroup parent)
{
  ...
  EventFields fields = new EventFields();
  cursor.moveToPosition (position);
  fields.title = cursor.getString (cursor.getColumnIndex (Instances.TITLE));
  fields.dtStart = cursor.getLong (cursor.getColumnIndex (Instances.BEGIN));
  fields.dtEnd = cursor.getLong (cursor.getColumnIndex (Instances.END));
  fields.iCalDuration = cursor.getString (cursor.getColumnIndex (Instances.DURATION));
  fields.rrule = cursor.getString (cursor.getColumnIndex (Instances.RRULE));
  ...
}

Here's the query:

@Override
public void refreshData (String constraint)
{
  long begin = ... some date ...
  long end = ... another date ...

  final Uri uri = Uri.parse(CalendarContract.Instances.CONTENT_URI + "/" + 
                            Long.toString(begin) + "/" + 
                            Long.toString(end));

  // Setup query  - projection ordering must match statics above.
  final String[] projection = new String[] {
    Instances._ID,
    Instances.EVENT_ID,
    Instances.TITLE,
    Instances.BEGIN,
    Instances.END,
    Instances.DURATION,
    Instances.RRULE,
    Instances.DESCRIPTION,
  };
  final String sortOrder = Instances.BEGIN;

  String selection = null;
  if (constraint != null)
    selection = Instances.TITLE + " like '%" + constraint.toString() + "%'"; 

  cursor = getActivity().getContentResolver().query (
    uri,
    projection, 
    selection,
    null,
    sortOrder);
}

For the example above, New Year's Day

New Year's day dtStart = 1419984000000 and

And another event which really starts at 4pm has

Roger          dtStart = 1420052400000
4

3 回答 3

3

正如评论中所讨论的,我们确定这是与以 UTC 显示时间的全天事件有关的问题。

看起来这就是Android 处理它的方式。

查看Android Docs 中的 Format Time 类

public boolean allDay
如果这是一个 allDay 事件,则为真。时、分、秒字段全部为零,并且日期在所有时区显示相同。

最后是CalendarContract.Events 文档

如果 allDay 设置为 1,则 eventTimezone 必须为 TIMEZONE_UTC 并且时间必须对应于午夜边界。

所以你通过格式化全天事件所做的事情是正确的

simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

更新

默认情况下,如果您没有明确设置 SimpleDateFormat 的时区,它将默认为您设备的本地时区。

您的 BEGIN 和 END 时间应该以 UTC 时间返回。

在 UTC 时区中,全天事件始终设置为午夜,因此将它们格式化为 UTC 时区以外的任何时间都会为您提供非午夜时间。

您可以使用继承字段检查日历事件实例的时区:

EVENT_TIMEZONE

于 2015-05-15T04:56:27.347 回答
0

尝试添加:formatter.setTimeZone(TimeZone.getTimeZone("US/Pacific"));

于 2015-05-14T03:41:58.307 回答
0

您实际上可以在日历上设置时区。仔细检查您比较的两个日历的时区是否设置为相同的值。

于 2015-05-18T14:05:53.013 回答