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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With