Запрос событий "all_day" с использованием CalendarContract.Instances приводит к неправильному часовому поясу

Я использую 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 ответа

Решение

Как обсуждалось в комментариях, мы определили, что это проблема, связанная с событиями на весь день, отображающими время в UTC.

Похоже, это то, как Android справляется с этим.

Рассматривая класс Format Time в Android Docs

публичный логический AllDay
True, если это событие allDay. Поля часа, минуты и секунды равны нулю, а дата отображается одинаково во всех часовых поясах.

И, наконец, на CalendarContract.Events документы

Если для allDay установлено значение 1, eventTimezone должен иметь значение TIMEZONE_UTC, а время должно соответствовать полуночной границе.

Так что то, что вы сделали, отформатировав события на весь день, правильно

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

Обновить

По умолчанию, если вы явно не установите часовой пояс вашего SimpleDateFormat, по умолчанию будет использоваться местный часовой пояс вашего устройства.

Ваши BEGIN и END должны возвращаться в UTC.

Мероприятия на весь день всегда установлены в полночь в часовом поясе UTC, поэтому при форматировании их во всем, кроме часового пояса UTC, вы получите не полночное время.

Вы можете проверить часовой пояс экземпляра события календаря, используя унаследованное поле:

EVENT_TIMEZONE

Вы действительно можете установить часовые пояса в ваших календарях. Дважды убедитесь, что для часовых поясов двух сравниваемых календарей установлено одинаковое значение.

Попробуйте добавить: formatter.setTimeZone(TimeZone.getTimeZone("US/Pacific"));

Другие вопросы по тегам