From c55e2c884743bf5dee7de8d0fda69db3510476fd Mon Sep 17 00:00:00 2001 From: Marc Blank Date: Thu, 5 May 2011 16:41:11 -0700 Subject: [PATCH] DO NOT MERGE: Fix serious DST issue with non-DST time zones * When finding a match for an EAS time zone without DST, we were checking the offset, but NOT the DST status; therefore, we could match the wrong time zone (depending on the order of items in the TZ database) * All users with events set up in non-DST timezones would have their events show up at the wrong time after a DST transition * The fix is to first check against the default time zone, and use that if it's a match; otherwise, to use the first time zone that matches both offset and DST availability Bug: 4337360 Change-Id: Ia26590972c1b0eab4640a3082881a28ee0a81622 --- .../exchange/utility/CalendarUtilities.java | 38 ++++++++++++++----- .../utility/CalendarUtilitiesTests.java | 9 +++++ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/com/android/exchange/utility/CalendarUtilities.java b/src/com/android/exchange/utility/CalendarUtilities.java index 7dd24e008..40848f88e 100644 --- a/src/com/android/exchange/utility/CalendarUtilities.java +++ b/src/com/android/exchange/utility/CalendarUtilities.java @@ -30,14 +30,15 @@ import com.android.exchange.EasSyncService; import com.android.exchange.SyncManager; import com.android.exchange.adapter.Serializer; import com.android.exchange.adapter.Tags; +import com.android.internal.util.ArrayUtils; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Entity; -import android.content.EntityIterator; import android.content.Entity.NamedContentValues; +import android.content.EntityIterator; import android.content.res.Resources; import android.net.Uri; import android.os.RemoteException; @@ -698,7 +699,7 @@ public class CalendarUtilities { TimeZone timeZone = sTimeZoneCache.get(timeZoneString); if (timeZone != null) { if (Eas.USER_LOG) { - SyncManager.log(TAG, " Using cached TimeZone " + timeZone.getDisplayName()); + SyncManager.log(TAG, " Using cached TimeZone " + timeZone.getID()); } } else { timeZone = tziStringToTimeZoneImpl(timeZoneString); @@ -739,14 +740,31 @@ public class CalendarUtilities { TimeZoneDate dstEnd = getTimeZoneDateFromSystemTime(timeZoneBytes, MSFT_TIME_ZONE_STANDARD_DATE_OFFSET); if (dstEnd == null) { - // In this case, there is no daylight savings time, so the only interesting data - // is the offset, and we know that all of the zoneId's match; we'll take the first - timeZone = TimeZone.getTimeZone(zoneIds[0]); - if (Eas.USER_LOG) { - SyncManager.log(TAG, "TimeZone without DST found by offset: " + - timeZone.getDisplayName()); + // If the default time zone is a match + TimeZone defaultTimeZone = TimeZone.getDefault(); + if (!defaultTimeZone.useDaylightTime() && + ArrayUtils.contains(zoneIds, defaultTimeZone.getID())) { + if (Eas.USER_LOG) { + SyncManager.log(TAG, "TimeZone without DST found to be default: " + + defaultTimeZone.getID()); + } + return defaultTimeZone; } - return timeZone; + // In this case, there is no daylight savings time, so the only interesting data + // for possible matches is the offset and DST availability; we'll take the first + // match for those + for (String zoneId: zoneIds) { + timeZone = TimeZone.getTimeZone(zoneId); + if (!timeZone.useDaylightTime()) { + if (Eas.USER_LOG) { + SyncManager.log(TAG, "TimeZone without DST found by offset: " + + timeZone.getID()); + } + return timeZone; + } + } + // None found, return null + return null; } else { TimeZoneDate dstStart = getTimeZoneDateFromSystemTime(timeZoneBytes, MSFT_TIME_ZONE_DAYLIGHT_DATE_OFFSET); @@ -791,7 +809,7 @@ public class CalendarUtilities { timeZone = TimeZone.getTimeZone(zoneIds[0]); if (Eas.USER_LOG) { SyncManager.log(TAG, "No TimeZone with correct DST settings; using first: " + - timeZone.getDisplayName()); + timeZone.getID()); } return timeZone; } diff --git a/tests/src/com/android/exchange/utility/CalendarUtilitiesTests.java b/tests/src/com/android/exchange/utility/CalendarUtilitiesTests.java index 65443fa02..43da5f018 100644 --- a/tests/src/com/android/exchange/utility/CalendarUtilitiesTests.java +++ b/tests/src/com/android/exchange/utility/CalendarUtilitiesTests.java @@ -91,6 +91,12 @@ public class CalendarUtilitiesTests extends AndroidTestCase { "AAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAACgARwBNAFQAKwAwADAAOgAwADAAKQAgAFQAaQBtAGUAIABaAG8A" + "bgBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAFAAEAAAAAAAAAxP///w=="; + // This time zone has no DST, but earlier, buggy code retrieved a TZ WITH DST + private static final String ARIZONA_TIME = + "pAEAAFUAUwAgAE0AbwB1AG4AdABhAGkAbgAgAFMAdABhAG4AZABhAHIAZAAgAFQAaQBtAGUAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFUAUwAgAE0AbwB1AG4AdABhAGkAbgAgAEQAYQB5AGwAaQBnAGgA" + + "dAAgAFQAaQBtAGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; + private static final String ORGANIZER = "organizer@server.com"; private static final String ATTENDEE = "attendee@server.com"; @@ -125,6 +131,9 @@ public class CalendarUtilitiesTests extends AndroidTestCase { tz = CalendarUtilities.tziStringToTimeZone(GMT_UNKNOWN_DAYLIGHT_TIME); int bias = tz.getOffset(System.currentTimeMillis()); assertEquals(0, bias); + // Make sure non-DST TZ's work properly + tz = CalendarUtilities.tziStringToTimeZone(ARIZONA_TIME); + assertEquals("America/Phoenix", tz.getID()); } public void testGenerateEasDayOfWeek() {