Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query of "all_day" events using CalendarContract.Instances results in wrong time zone

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
like image 942
Peri Hartman Avatar asked Dec 17 '14 00:12

Peri Hartman


1 Answers

As discussed in the comments, we determined that this is a problem related to All Day events displaying times in UTC.

It looks like this is just how Android handles it.

Looking at the Format Time class in the Android Docs

public boolean allDay
True if this is an allDay event. The hour, minute, second fields are all zero, and the date is displayed the same in all time zones.

And finally on the CalendarContract.Events docs

If allDay is set to 1 eventTimezone must be TIMEZONE_UTC and the time must correspond to a midnight boundary.

So what you have done by formatting all day events is correct

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

Update

By default, if you don't explicitly set the timezone of your SimpleDateFormat, it will default to your device's local timezone.

Your BEGIN and END times should come back in UTC time.

All Day Events are always set to midnight in the UTC timezone, so formatting them in anything but the UTC time zone will give you a non-midnight time.

You can check the Calendar Event Instance's timezone using the inherited field:

EVENT_TIMEZONE

like image 192
EdmundYeung99 Avatar answered Oct 10 '22 06:10

EdmundYeung99