Per*_*man 6 android calendarcontract
我正在使用CalendarContract.Instances来获取一组日历事件.一般来说,我的查询工作正常.但是,"假期"日历中事件的开始和结束时间将返回错误的时区.我个人日历中的活动来自正确的时间.
例如:
New Year's day "begins" at 04:00 PM, 31 Dec 2014.
Run Code Online (Sandbox Code Playgroud)
在哪里
Opera "begins" at 02:00 PM, 11 Jan 2015.
Run Code Online (Sandbox Code Playgroud)
我使用完全相同的代码来显示两者:
  SimpleDateFormat formatter = new SimpleDateFormat ("hh:mm a, d MMM yyyy", Locale.US);
  logD (prefix + i + ": " + formatter.format (data.startTime) + "; " + data.note);
Run Code Online (Sandbox Code Playgroud)
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));
  ...
}
Run Code Online (Sandbox Code Playgroud)
这是查询:
@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);
}
Run Code Online (Sandbox Code Playgroud)
对于上面的例子,元旦
New Year's day dtStart = 1419984000000 and
Run Code Online (Sandbox Code Playgroud)
另一个真正在下午4点开始的活动已经开始
Roger          dtStart = 1420052400000
Run Code Online (Sandbox Code Playgroud)
    正如评论中所讨论的,我们确定这是与以 UTC 格式显示时间的全天事件相关的问题。
看起来Android 就是这么处理的。
public boolean allDay
如果这是一个 allDay 事件,则为 true。小时、分钟、秒字段均为零,并且日期在所有时区中显示相同。
如果 allDay 设置为 1 eventTimezone 必须为 TIMEZONE_UTC 并且时间必须对应于午夜边界。
所以你通过格式化全天事件所做的事情是正确的
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Run Code Online (Sandbox Code Playgroud)
更新
默认情况下,如果您没有明确设置 SimpleDateFormat 的时区,它将默认为您设备的本地时区。
您的 BEGIN 和 END 时间应以 UTC 时间返回。
全天活动始终设置为 UTC 时区的午夜,因此以 UTC 时区以外的任何格式设置它们将为您提供非午夜时间。
您可以使用继承字段检查日历事件实例的时区:
EVENT_TIMEZONE