查询" all_day"使用CalendarContract.Instances的事件导致错误的时区

时间:2014-12-17 00:22:53

标签: android calendarcontract

我正在使用CalendarContract.Instances来获取一组日历事件。一般来说,我的查询工作正常。但是,“假期”日历中事件的开始和结束时间将返回错误的时区。我个人日历中的活动来自正确的时间。

例如:

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

其中

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

我使用完全相同的代码来显示两者:

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

其中data.startTime映射到Instances.BEGIN,data.note映射到Instances.TITLE。歌剧院正好在正确的时间出现,新年的一天显然是8小时(我在美国太平洋时区)。

如果我在Android日历应用中查看这些内容,则会显示正确的时间。

显然,我可以查看事件来自哪个日历,并相应地设置时区以使其显示正确的时间。但是,我希望有一个我不知道的更合适的解决方案。

这是从代码中获取事件值的代码片段:

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

以下是查询:

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

上述例子,元旦

New Year's day dtStart = 1419984000000 and

另一个真正在下午4点开始的活动

Roger          dtStart = 1420052400000

3 个答案:

答案 0 :(得分:3)

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

看起来这是just how Android handles it

查看Format Time class in the Android Docs

  

public boolean allDay
  如果这是一个allDay事件,则为True。小时,分钟,秒字段均为零,日期在所有时区显示相同。

最后在CalendarContract.Events docs

  

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

因此,您通过格式化全天事件所做的工作是正确的

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

<强>更新

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

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

所有日期事件始终设置为UTC时区的午夜,因此除了UTC时区之外的任何其他格式都将为您提供非午夜时间。

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

  

EVENT_TIMEZONE

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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