Clean up VCALENDAR/TIME_ZONE_INFORMATION code
* Fix the transition times so that they occur at the hour * Remove an unused variable * Fix a reference to Calendar.HOUR that should have been Calendar.HOUR_OF_DAY * Confirm that unit tests work properly Change-Id: I3eaf31d160e97b5f3ba59c83878359085aea960d
This commit is contained in:
parent
a0b4907ca5
commit
d5822018fb
|
@ -186,9 +186,8 @@ public class CalendarUtilities {
|
|||
setWord(bytes, offset + MSFT_SYSTEMTIME_MINUTE, minute);
|
||||
}
|
||||
|
||||
// Write SYSTEMTIME data into a byte array (this will either be for the standard or daylight
|
||||
// transition)
|
||||
static void putTimeInMillisIntoSystemTime(byte[] bytes, int offset, long millis) {
|
||||
// Write a transition time into SYSTEMTIME data (via an offset into a byte array)
|
||||
static void putTransitionMillisIntoSystemTime(byte[] bytes, int offset, long millis) {
|
||||
GregorianCalendar cal = new GregorianCalendar(TimeZone.getDefault());
|
||||
// Round to the next highest minute; we always write seconds as zero
|
||||
cal.setTimeInMillis(millis + 30*SECONDS);
|
||||
|
@ -204,8 +203,8 @@ public class CalendarUtilities {
|
|||
setWord(bytes, offset + MSFT_SYSTEMTIME_DAY, wom < 0 ? 5 : wom);
|
||||
|
||||
// Turn hours/minutes into ms from midnight (per TimeZone)
|
||||
setWord(bytes, offset + MSFT_SYSTEMTIME_HOUR, cal.get(Calendar.HOUR));
|
||||
setWord(bytes, offset + MSFT_SYSTEMTIME_MINUTE, cal.get(Calendar.MINUTE));
|
||||
setWord(bytes, offset + MSFT_SYSTEMTIME_HOUR, getTrueTransitionHour(cal));
|
||||
setWord(bytes, offset + MSFT_SYSTEMTIME_MINUTE, getTrueTransitionMinute(cal));
|
||||
}
|
||||
|
||||
// Build a TimeZoneDate structure from a SYSTEMTIME within a byte array at a given offset
|
||||
|
@ -273,15 +272,17 @@ public class CalendarUtilities {
|
|||
* @param startInDaylightTime whether daylight time is in effect at the startTime
|
||||
* @return a GregorianCalendar representing the transition or null if none
|
||||
*/
|
||||
static /*package*/ GregorianCalendar findTransitionDate(TimeZone tz, long startTime, long endTime,
|
||||
boolean startInDaylightTime) {
|
||||
static /*package*/ GregorianCalendar findTransitionDate(TimeZone tz, long startTime,
|
||||
long endTime, boolean startInDaylightTime) {
|
||||
long startingEndTime = endTime;
|
||||
Date date = null;
|
||||
|
||||
// We'll keep splitting the difference until we're within a minute
|
||||
while ((endTime - startTime) > MINUTES) {
|
||||
long checkTime = ((startTime + endTime) / 2) + 1;
|
||||
date = new Date(checkTime);
|
||||
if (tz.inDaylightTime(date) != startInDaylightTime) {
|
||||
boolean inDaylightTime = tz.inDaylightTime(date);
|
||||
if (inDaylightTime != startInDaylightTime) {
|
||||
endTime = checkTime;
|
||||
} else {
|
||||
startTime = checkTime;
|
||||
|
@ -293,17 +294,9 @@ public class CalendarUtilities {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Set up our calendar
|
||||
// Set up our calendar and return it
|
||||
GregorianCalendar calendar = new GregorianCalendar(tz);
|
||||
calendar.setTimeInMillis(startInDaylightTime ? startTime : endTime);
|
||||
int min = calendar.get(Calendar.MINUTE);
|
||||
if (min == 59) {
|
||||
// If we're at XX:59:ZZ, round up to the next minute
|
||||
calendar.add(Calendar.SECOND, 60 - calendar.get(Calendar.SECOND));
|
||||
} else if (min == 0) {
|
||||
// If we're at XX:00:ZZ, round down to the minute
|
||||
calendar.add(Calendar.SECOND, -calendar.get(Calendar.SECOND));
|
||||
}
|
||||
calendar.setTimeInMillis(startTime);
|
||||
return calendar;
|
||||
}
|
||||
|
||||
|
@ -576,12 +569,13 @@ public class CalendarUtilities {
|
|||
writer.writeTag("TZOFFSETFROM", standardOffsetString);
|
||||
writer.writeTag("TZOFFSETTO", daylightOffsetString);
|
||||
writer.writeTag("DTSTART",
|
||||
millisToVCalendarTime(toDaylightCalendars[0].getTimeInMillis(), tz, true));
|
||||
transitionMillisToVCalendarTime(
|
||||
toDaylightCalendars[0].getTimeInMillis(), tz, true));
|
||||
if (hasRule) {
|
||||
writer.writeTag("RRULE", daylightRule.toString());
|
||||
} else {
|
||||
for (int i = 1; i < maxYears; i++) {
|
||||
writer.writeTag("RDATE", millisToVCalendarTime(
|
||||
writer.writeTag("RDATE", transitionMillisToVCalendarTime(
|
||||
toDaylightCalendars[i].getTimeInMillis(), tz, true));
|
||||
}
|
||||
}
|
||||
|
@ -591,12 +585,13 @@ public class CalendarUtilities {
|
|||
writer.writeTag("TZOFFSETFROM", daylightOffsetString);
|
||||
writer.writeTag("TZOFFSETTO", standardOffsetString);
|
||||
writer.writeTag("DTSTART",
|
||||
millisToVCalendarTime(toStandardCalendars[0].getTimeInMillis(), tz, false));
|
||||
transitionMillisToVCalendarTime(
|
||||
toStandardCalendars[0].getTimeInMillis(), tz, false));
|
||||
if (hasRule) {
|
||||
writer.writeTag("RRULE", standardRule.toString());
|
||||
} else {
|
||||
for (int i = 1; i < maxYears; i++) {
|
||||
writer.writeTag("RDATE", millisToVCalendarTime(
|
||||
writer.writeTag("RDATE", transitionMillisToVCalendarTime(
|
||||
toStandardCalendars[i].getTimeInMillis(), tz, true));
|
||||
}
|
||||
}
|
||||
|
@ -649,12 +644,12 @@ public class CalendarUtilities {
|
|||
// Write month, day of week, week, hour, minute
|
||||
putRuleIntoTimeZoneInformation(tziBytes, MSFT_TIME_ZONE_STANDARD_DATE_OFFSET,
|
||||
standardRule,
|
||||
toStandardCalendars[0].get(Calendar.HOUR),
|
||||
toStandardCalendars[0].get(Calendar.MINUTE));
|
||||
getTrueTransitionHour(toStandardCalendars[0]),
|
||||
getTrueTransitionMinute(toStandardCalendars[0]));
|
||||
putRuleIntoTimeZoneInformation(tziBytes, MSFT_TIME_ZONE_DAYLIGHT_DATE_OFFSET,
|
||||
daylightRule,
|
||||
toDaylightCalendars[0].get(Calendar.HOUR),
|
||||
toDaylightCalendars[0].get(Calendar.MINUTE));
|
||||
getTrueTransitionHour(toDaylightCalendars[0]),
|
||||
getTrueTransitionMinute(toDaylightCalendars[0]));
|
||||
} else {
|
||||
// If there's no rule, we'll use the first transition to standard/to daylight
|
||||
// And indicate that it's just for this year...
|
||||
|
@ -663,10 +658,10 @@ public class CalendarUtilities {
|
|||
long daylightTransition = findNextTransition(now, toDaylightCalendars);
|
||||
// If we can't find transitions, we can't do DST
|
||||
if (standardTransition != 0 && daylightTransition != 0) {
|
||||
putTimeInMillisIntoSystemTime(tziBytes, MSFT_TIME_ZONE_STANDARD_DATE_OFFSET,
|
||||
standardTransition);
|
||||
putTimeInMillisIntoSystemTime(tziBytes, MSFT_TIME_ZONE_DAYLIGHT_DATE_OFFSET,
|
||||
daylightTransition);
|
||||
putTransitionMillisIntoSystemTime(tziBytes,
|
||||
MSFT_TIME_ZONE_STANDARD_DATE_OFFSET, standardTransition);
|
||||
putTransitionMillisIntoSystemTime(tziBytes,
|
||||
MSFT_TIME_ZONE_DAYLIGHT_DATE_OFFSET, daylightTransition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -831,12 +826,47 @@ public class CalendarUtilities {
|
|||
}
|
||||
|
||||
/**
|
||||
* Generate a date/time string suitable for VTIMEZONE, the format is YYYYMMDDTHHMMSS
|
||||
* @param millis a time in milliseconds
|
||||
* Return the true minute at which a transition occurs
|
||||
* Our transition time should be the in the minute BEFORE the transition
|
||||
* If this minute is 59, set minute to 0 and increment the hour
|
||||
* NOTE: We don't want to add a minute and retrieve minute/hour from the Calendar, because
|
||||
* Calendar time will itself be influenced by the transition! So adding 1 minute to
|
||||
* 01:59 (assume PST->PDT) will become 03:00, which isn't what we want (we want 02:00)
|
||||
*
|
||||
* @param calendar the calendar holding the transition date/time
|
||||
* @return the true minute of the transition
|
||||
*/
|
||||
static public int getTrueTransitionMinute(GregorianCalendar calendar) {
|
||||
int minute = calendar.get(Calendar.MINUTE);
|
||||
if (minute == 59) {
|
||||
minute = 0;
|
||||
}
|
||||
return minute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the true hour at which a transition occurs
|
||||
* See description for getTrueTransitionMinute, above
|
||||
* @param calendar the calendar holding the transition date/time
|
||||
* @return the true hour of the transition
|
||||
*/
|
||||
static public int getTrueTransitionHour(GregorianCalendar calendar) {
|
||||
int hour = calendar.get(Calendar.HOUR_OF_DAY);
|
||||
hour++;
|
||||
if (hour == 24) {
|
||||
hour = 0;
|
||||
}
|
||||
return hour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a date/time string suitable for VTIMEZONE from a transition time in millis
|
||||
* The format is YYYYMMDDTHHMMSS
|
||||
* @param millis a transition time in milliseconds
|
||||
* @param tz a time zone
|
||||
* @param dst whether we're entering daylight time
|
||||
*/
|
||||
static public String millisToVCalendarTime(long millis, TimeZone tz, boolean dst) {
|
||||
static public String transitionMillisToVCalendarTime(long millis, TimeZone tz, boolean dst) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
GregorianCalendar cal = new GregorianCalendar(tz);
|
||||
cal.setTimeInMillis(millis);
|
||||
|
@ -844,18 +874,9 @@ public class CalendarUtilities {
|
|||
sb.append(formatTwo(cal.get(Calendar.MONTH) + 1));
|
||||
sb.append(formatTwo(cal.get(Calendar.DAY_OF_MONTH)));
|
||||
sb.append('T');
|
||||
// If we're entering daylight time, go back an hour to compensate for the singularity
|
||||
if (dst && (tz.getDSTSavings() == HOURS)) {
|
||||
int hour = cal.get(Calendar.HOUR_OF_DAY);
|
||||
if (hour > 0) {
|
||||
hour--;
|
||||
}
|
||||
sb.append(formatTwo(hour));
|
||||
} else {
|
||||
sb.append(formatTwo(cal.get(Calendar.HOUR_OF_DAY)));
|
||||
}
|
||||
sb.append(formatTwo(cal.get(Calendar.MINUTE)));
|
||||
sb.append(formatTwo(cal.get(Calendar.SECOND)));
|
||||
sb.append(formatTwo(getTrueTransitionHour(cal)));
|
||||
sb.append(formatTwo(getTrueTransitionMinute(cal)));
|
||||
sb.append(formatTwo(0));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -487,7 +487,6 @@ public class CalendarUtilitiesTests extends AndroidTestCase {
|
|||
BlockHash (String _name, BufferedReader reader) throws IOException {
|
||||
name = _name;
|
||||
String lastField = null;
|
||||
int lastLength = 0;
|
||||
String lastValue = null;
|
||||
while (true) {
|
||||
// Get a line; we're done if it's null
|
||||
|
@ -504,7 +503,6 @@ public class CalendarUtilitiesTests extends AndroidTestCase {
|
|||
if (line.charAt(0) == '\t') {
|
||||
// Remember the line and length
|
||||
lastValue = line.substring(1);
|
||||
lastLength = line.length();
|
||||
// Save the concatenation of old and new values
|
||||
hash.put(lastField, hash.get(lastField) + lastValue);
|
||||
continue;
|
||||
|
@ -528,7 +526,6 @@ public class CalendarUtilitiesTests extends AndroidTestCase {
|
|||
break;
|
||||
}
|
||||
|
||||
lastLength = line.length();
|
||||
// Save it away and continue
|
||||
hash.put(lastField, lastValue);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue