15
votes

I wrote a simple code to insert an all day event into the calendar, using the tutorial from the official site. http://developer.android.com/guide/topics/providers/calendar-provider.html

    ContentResolver cr = context.getContentResolver();
    ContentValues values = new ContentValues();
    values.put(Events.DTSTART, dueDate.getTime());
    values.put(Events.ALL_DAY, true);   
    values.put(Events.DTEND, dueDate.getTime());
    values.put(Events.TITLE, "Some Event");
    values.put(Events.CALENDAR_ID, mCalID);
    TimeZone tz = TimeZone.getDefault();
    values.put(Events.EVENT_TIMEZONE, tz.getID());
   Uri uri = cr.insert(Events.CONTENT_URI, values);

I found that when I opened the Google Calendar app on the my Acer device running 4.03, the date entered had been shifted back by 1 day. My local timezone is Sydney which is GMT+10.

So I went to settings changed the local time zone to American Eastern (GMT -5) and ran the same code and there was no shift in the dates. Then I changed the timezone to GMT+2, Istanbul and there was a shift in the dates. Then I changed to London GMT 0, and there was no shift.

When I did non all day events the correct times were entered into the calendar regardless of the timezone.

The closest bug report I found was this http://code.google.com/p/android/issues/detail?id=14051

Am I missing something in the code, or have others also encountered this.

Edit On further inspection when reading Event data using content resolver

  ContentResolver cr = context.getContentResolver();
Uri uri =  CalendarContract.Events.CONTENT_URI; 
String selection =CalendarContract.Events._ID + "=?";
String [] selectionArgs = new String[]{String.valueOf(eventID)}; 

The value of the long when convert to date was the correct date and time eg. 14th Feb 2013 12.00 AEST (Sydney Time). So the problem must be in the way Google Calendar is reading in these values. When I added an all day event manually from the Calendar application in Android, and the read the time using content resolver it was the date and 11.00 am in AEST (Sydney Time), which corresponds to the +11 GMT off set in Sydney. So all day events need to be entered in GMT to avoid this, but there is no mention of this in the documentation.

So now I am shifting the time, to avoid this problem.

3

3 Answers

6
votes

A couple ideas:

  1. time zone "independence" of all-day events (treated as if having GMT) [1] [2]
  2. international date line

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

[2]http://developer.android.com/reference/android/provider/CalendarContract.Events.html

0
votes

If my event was an all day event, I converted it to local time. This made the all day event stay on the correct date. If it is not all day I left it as normal. I don't think this is a great solution, but it works and if anyone sees a problem with it then let me know.

        var startDate = yourCalendarEvent.StartDate;
        if (yourCalendarEvent.IsAllDay)
        {
            startDate = startDate.ToLocalTime();
        }
        Java.Util.GregorianCalendar calStartDate = new Java.Util.GregorianCalendar(startDate.Year, startDate.Month - 1, startDate.Day, startDate.Hour, startDate.Minute, startDate.Second);
        intent.PutExtra(CalendarContract.ExtraEventBeginTime, calStartDate.TimeInMillis);
0
votes

The docs for CalendarContract.EventsColumns state "If allDay is set to 1 eventTimezone must be TIMEZONE_UTC and the time must correspond to a midnight boundary."

My solution to ensure that expected dates would be returned after querying the API was to a)Set the start and end event values with dates aligned to UTC. b)Adjust the time returned after querying to take the device timezone and DST into account.

a)

@Before
public void setup(){
    ...
    mJavaCalendar = Calendar.getInstance();
    mInputStart = getUtcDate(
            mJavaCalendar.get(Calendar.YEAR),
            mJavaCalendar.get(Calendar.MONTH),
            mJavaCalendar.get(Calendar.DAY_OF_MONTH));
}

private long getUtcDate(int year, int month, int day){
    Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    calendar.set(year, month, day,0, 0, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTimeInMillis();
}

@Test
public void jCalAlldayTzDflt0000To2400(){
    mTodayEvent.setEventStart(mInputStart);
    mTodayEvent.setEventEnd(mTodayEvent.getEventStart() +  DateUtils.DAY_IN_MILLIS);
    mTodayEvent.setAllDay(true);
    ...
}

b)

public static long getTzAdjustedDate(long date){
    TimeZone tzDefault = TimeZone.getDefault();
    return date - tzDefault.getOffset(date);
}

public void getCorrectDate(cursor){
    isAllDay() == 1 ? DateTimeUtils.getTzAdjustedDate(cursor.getLong(INST_PROJECTION_BEGIN_INDEX)) :
            cursor.getLong(INST_PROJECTION_BEGIN_INDEX));

I hope this helps.