// We handle most fields in the same way. The algorithm is to add
// a computed amount of millis to the current millis. The only
- // wrinkle is with DST -- for some fields, like the DAY_OF_MONTH,
+ // wrinkle is with DST (and/or a change to the zone's UTC offset, which
+ // we'll include with DST) -- for some fields, like the DAY_OF_MONTH,
// we don't want the HOUR to shift due to changes in DST. If the
// result of the add operation is to move from DST to Standard, or
// vice versa, we need to adjust by an hour forward or back,
int dst = 0;
int hour = 0;
if (keepHourInvariant) {
- dst = get(DST_OFFSET);
+ dst = get(DST_OFFSET) + get(ZONE_OFFSET);
hour = internalGet(HOUR_OF_DAY);
}
setTimeInMillis(getTimeInMillis() + delta);
if (keepHourInvariant) {
- dst -= get(DST_OFFSET);
+ dst -= get(DST_OFFSET) + get(ZONE_OFFSET);
if (dst != 0) {
// We have done an hour-invariant adjustment but the
// DST offset has altered. We adjust millis to keep
/**
*******************************************************************************
- * Copyright (C) 2000-2009, International Business Machines Corporation and *
+ * Copyright (C) 2000-2009,2011 International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
y + "/" + (m+1) + "/" + d);
}
+ // Verify that add works across ZONE_OFFSET and DST_OFFSET transitions
+ public void TestAddAcrossOffsetTransitions() {
+ class TransitionItem {
+ private String zoneName;
+ private int year;
+ private int month;
+ private int day;
+ private int hour;
+ TransitionItem(String zn, int y, int m, int d, int h) {
+ zoneName = zn;
+ year = y;
+ month = m;
+ day = d;
+ hour = h;
+ }
+ public String getZoneName() { return zoneName; }
+ public int getYear() { return year; }
+ public int getMonth() { return month; }
+ public int getDay() { return day; }
+ public int getHour() { return hour; }
+ }
+ final TransitionItem[] transitionItems = {
+ new TransitionItem( "America/Caracas", 2007, Calendar.DECEMBER, 8, 10 ), // day before change in ZONE_OFFSET
+ new TransitionItem( "US/Pacific", 2011, Calendar.MARCH, 12, 10 ), // day before change in DST_OFFSET
+ };
+ for (TransitionItem transitionItem: transitionItems) {
+ String zoneName = transitionItem.getZoneName();
+ Calendar cal = null;
+ try {
+ cal = Calendar.getInstance(TimeZone.getTimeZone(zoneName), Locale.ENGLISH);
+ } catch (Exception e) {
+ errln("Error: Calendar.getInstance fails for zone " + zoneName);
+ continue;
+ }
+ int itemHour = transitionItem.getHour();
+ cal.set( transitionItem.getYear(), transitionItem.getMonth(), transitionItem.getDay(), itemHour, 0 );
+ cal.add( Calendar.DATE, 1 );
+ int hr = cal.get( Calendar.HOUR_OF_DAY );
+ if ( hr != itemHour ) {
+ errln("Error: Calendar.add produced wrong hour " + hr + " when adding day across transition for zone " + zoneName);
+ } else {
+ cal.add( Calendar.DATE, -1 );
+ hr = cal.get( Calendar.HOUR_OF_DAY );
+ if ( hr != itemHour ) {
+ errln("Error: Calendar.add produced wrong hour " + hr + " when subtracting day across transition for zone " + zoneName);
+ }
+ }
+ }
+ }
+
// Verify that setting fields works. This test fails when an exception is thrown.
public void TestFieldSet4781() {
try {