ICU-21490 Exposing getOffsetFromLocal for ICU4J
See #1609
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/OlsonTimeZone.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/OlsonTimeZone.java
index 0d315b1..d514966 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/OlsonTimeZone.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/OlsonTimeZone.java
@@ -280,11 +280,11 @@
*/
@Override
public void getOffsetFromLocal(long date,
- int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) {
+ LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets) {
if (finalZone != null && date >= finalStartMillis) {
finalZone.getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, offsets);
} else {
- getHistoricalOffset(date, true, nonExistingTimeOpt, duplicatedTimeOpt, offsets);
+ getHistoricalOffset(date, true, getLocalOptionValue(nonExistingTimeOpt), getLocalOptionValue(duplicatedTimeOpt), offsets);
}
}
@@ -1296,4 +1296,4 @@
tz.isFrozen = false;
return tz;
}
-}
+}
\ No newline at end of file
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
index 040258c..05131f5 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
@@ -37,6 +37,7 @@
import com.ibm.icu.text.TimeZoneFormat.Style;
import com.ibm.icu.text.TimeZoneFormat.TimeType;
import com.ibm.icu.util.BasicTimeZone;
+import com.ibm.icu.util.BasicTimeZone.LocalOption;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.HebrewCalendar;
import com.ibm.icu.util.Output;
@@ -2710,10 +2711,10 @@
if (btz != null) {
if (tztype == TimeType.STANDARD) {
btz.getOffsetFromLocal(localMillis,
- BasicTimeZone.LOCAL_STD, BasicTimeZone.LOCAL_STD, offsets);
+ LocalOption.STANDARD_FORMER, LocalOption.STANDARD_LATTER, offsets);
} else {
btz.getOffsetFromLocal(localMillis,
- BasicTimeZone.LOCAL_DST, BasicTimeZone.LOCAL_DST, offsets);
+ LocalOption.DAYLIGHT_FORMER, LocalOption.DAYLIGHT_LATTER, offsets);
}
} else {
// No good way to resolve ambiguous time at transition,
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/BasicTimeZone.java b/icu4j/main/classes/core/src/com/ibm/icu/util/BasicTimeZone.java
index abef756..5d56a39 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/util/BasicTimeZone.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/util/BasicTimeZone.java
@@ -36,7 +36,7 @@
/**
* {@icu} Returns the first time zone transition after the base time.
* <p>Example code:{@.jcite com.ibm.icu.samples.util.timezone.BasicTimeZoneExample:---getNextTransitionExample}
- *
+ *
* @param base The base time.
* @param inclusive Whether the base time is inclusive or not.
*
@@ -105,7 +105,7 @@
*
* @stable ICU 3.8
*/
- public boolean hasEquivalentTransitions(TimeZone tz, long start, long end,
+ public boolean hasEquivalentTransitions(TimeZone tz, long start, long end,
boolean ignoreDstAmount) {
if (this == tz) {
return true;
@@ -244,7 +244,7 @@
}
BitSet isProcessed = new BitSet(all.length);
- List<TimeZoneRule> filteredRules = new LinkedList<TimeZoneRule>();
+ List<TimeZoneRule> filteredRules = new LinkedList<>();
// Create initial rule
TimeZoneRule initial = new InitialTimeZoneRule(tzt.getTo().getName(),
@@ -434,16 +434,16 @@
// Check if the next next transition is either DST->STD or STD->DST
// and within roughly 1 year from the next transition
if (((tr.getFrom().getDSTSavings() == 0 && tr.getTo().getDSTSavings() != 0)
- || (tr.getFrom().getDSTSavings() != 0
+ || (tr.getFrom().getDSTSavings() != 0
&& tr.getTo().getDSTSavings() == 0))
&& nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) {
// Generate another DOW rule
dtfields = Grego.timeToFields(tr.getTime()
- + tr.getFrom().getRawOffset() + tr.getFrom().getDSTSavings(),
+ + tr.getFrom().getRawOffset() + tr.getFrom().getDSTSavings(),
dtfields);
- weekInMonth = Grego.getDayOfWeekInMonth(dtfields[0], dtfields[1],
+ weekInMonth = Grego.getDayOfWeekInMonth(dtfields[0], dtfields[1],
dtfields[2]);
- dtr = new DateTimeRule(dtfields[1], weekInMonth, dtfields[3],
+ dtr = new DateTimeRule(dtfields[1], weekInMonth, dtfields[3],
dtfields[5], DateTimeRule.WALL_TIME);
secondRule = new AnnualTimeZoneRule(tr.getTo().getName(),
tr.getTo().getRawOffset(), tr.getTo().getDSTSavings(),
@@ -472,22 +472,22 @@
&& tr.getTo().getDSTSavings() == 0)) {
// Generate another DOW rule
dtfields = Grego.timeToFields(tr.getTime()
- + tr.getFrom().getRawOffset() + tr.getFrom().getDSTSavings(),
+ + tr.getFrom().getRawOffset() + tr.getFrom().getDSTSavings(),
dtfields);
- weekInMonth = Grego.getDayOfWeekInMonth(dtfields[0], dtfields[1],
+ weekInMonth = Grego.getDayOfWeekInMonth(dtfields[0], dtfields[1],
dtfields[2]);
- dtr = new DateTimeRule(dtfields[1], weekInMonth, dtfields[3],
+ dtr = new DateTimeRule(dtfields[1], weekInMonth, dtfields[3],
dtfields[5], DateTimeRule.WALL_TIME);
// second rule raw/dst offsets should match raw/dst offsets
// at the given time
secondRule = new AnnualTimeZoneRule(
- tr.getTo().getName(), initialRaw, initialDst, dtr,
+ tr.getTo().getName(), initialRaw, initialDst, dtr,
annualRules[0].getStartYear() - 1, AnnualTimeZoneRule.MAX_YEAR);
// Check if this rule start after the first rule after the
// specified date
- Date d = secondRule.getNextStart(date, tr.getFrom().getRawOffset(),
+ Date d = secondRule.getNextStart(date, tr.getFrom().getRawOffset(),
tr.getFrom().getDSTSavings(), false);
if (d.getTime() > nextTransitionTime) {
// We can use this rule as the second transition rule
@@ -536,44 +536,123 @@
}
/**
- * {@icu} The time type option for standard time used by
- * {@link #getOffsetFromLocal(long, int, int, int[])}
+ * {@icu} Options used by {@link #getOffsetFromLocal(long, LocalOption, LocalOption, int[])}
+ * to specify how to interpret an input time when it does not exist, or when it is ambiguous,
+ * around a time zone transition.
+ *
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
+ */
+ public static enum LocalOption {
+ /**
+ * An input time is always interpreted as local time before
+ * a time zone transition.
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
+ */
+ FORMER(0x04),
+ /**
+ * An input time is always interpreted as local time after
+ * a time zone transition.
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
+ */
+ LATTER(0x0C),
+ /**
+ * An input time is interpreted as standard time when local
+ * time is switched to/from daylight saving time. When both
+ * sides of a time zone transition are standard time,
+ * or daylight saving time, the local time before the
+ * transition is used.
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
+ */
+ STANDARD_FORMER(0x05),
+ /**
+ * An input time is interpreted as standard time when local
+ * time is switched to/from daylight saving time. When both
+ * sides of a time zone transition are standard time,
+ * or daylight saving time, the local time after the
+ * transition is used.
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
+ */
+ STANDARD_LATTER(0x0D),
+ /**
+ * An input time is interpreted as daylight saving time when
+ * local time is switched to/from standard time. When both
+ * sides of a time zone transition are standard time,
+ * or daylight saving time, the local time before the
+ * transition is used.
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
+ */
+ DAYLIGHT_FORMER(0x07),
+ /**
+ * An input time is interpreted as daylight saving time when
+ * local time is switched to/from standard time. When both
+ * sides of a time zone transition are standard time,
+ * or daylight saving time, the local time after the
+ * transition is used.
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
+ */
+ DAYLIGHT_LATTER(0x0F);
+
+ private int flagVal;
+
+ LocalOption(int flagVal) {
+ this.flagVal = flagVal;
+ }
+ }
+
+ /**
+ * Get {@link LocalOption}'s internal flag value. This is used by ICU internal
+ * implementation only.
+ * @param locOpt A LocalOption
+ * @return LocalOption's internal flag value.
* @internal
* @deprecated This API is ICU internal only.
*/
@Deprecated
- public static final int LOCAL_STD = 0x01;
+ protected static int getLocalOptionValue(LocalOption locOpt) {
+ return locOpt.flagVal;
+ }
/**
- * {@icu} The time type option for daylight saving time used by
- * {@link #getOffsetFromLocal(long, int, int, int[])}
+ * The time type option for standard time used by internal implementation.
* @internal
* @deprecated This API is ICU internal only.
*/
@Deprecated
- public static final int LOCAL_DST = 0x03;
+ protected static final int LOCAL_STD = 0x01;
/**
- * {@icu} The option designate former time to be used by
- * {@link #getOffsetFromLocal(long, int, int, int[])}
+ * The time type option for daylight saving time used internally.
* @internal
* @deprecated This API is ICU internal only.
*/
@Deprecated
- public static final int LOCAL_FORMER = 0x04;
+ protected static final int LOCAL_DST = 0x03;
/**
- * {@icu} The option designate latter time to be used by
- * {@link #getOffsetFromLocal(long, int, int, int[])}
+ * The option designate former time used by internal implementation.
* @internal
* @deprecated This API is ICU internal only.
*/
@Deprecated
- public static final int LOCAL_LATTER = 0x0C;
+ protected static final int LOCAL_FORMER = 0x04;
/**
- * {@icu} The bit mask for the time type option used by
- * {@link #getOffsetFromLocal(long, int, int, int[])}
+ * The option designate latter time used by internal implementation.
+ * @internal
+ * @deprecated This API is ICU internal only.
+ */
+ @Deprecated
+ protected static final int LOCAL_LATTER = 0x0C;
+
+ /**
+ * The bit mask for the time type option used by internal implementation.
* @internal
* @deprecated This API is ICU internal only.
*/
@@ -581,8 +660,7 @@
protected static final int STD_DST_MASK = 0x03;
/**
- * {@icu} The bit mask for the former/latter option used by
- * {@link #getOffsetFromLocal(long, int, int, int[])}
+ * The bit mask for the former/latter option used by internal implementation.
* @internal
* @deprecated This API is ICU internal only.
*/
@@ -591,12 +669,11 @@
/**
* {@icu} Returns time zone offsets from local wall time.
- * @internal
- * @deprecated This API is ICU internal only.
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
*/
- @Deprecated
public void getOffsetFromLocal(long date,
- int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) {
+ LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets) {
throw new IllegalStateException("Not implemented");
}
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/Calendar.java b/icu4j/main/classes/core/src/com/ibm/icu/util/Calendar.java
index 0aeb7e9..edfc8a7 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/util/Calendar.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/util/Calendar.java
@@ -29,6 +29,7 @@
import com.ibm.icu.text.DateFormatSymbols;
import com.ibm.icu.text.DateTimePatternGenerator;
import com.ibm.icu.text.SimpleDateFormat;
+import com.ibm.icu.util.BasicTimeZone.LocalOption;
import com.ibm.icu.util.ULocale.Category;
/**
@@ -5725,8 +5726,8 @@
int[] offsets = new int[2];
long wall = millis + millisInDay;
if (zone instanceof BasicTimeZone) {
- int duplicatedTimeOpt = (repeatedWallTime == WALLTIME_FIRST) ? BasicTimeZone.LOCAL_FORMER : BasicTimeZone.LOCAL_LATTER;
- int nonExistingTimeOpt = (skippedWallTime == WALLTIME_FIRST) ? BasicTimeZone.LOCAL_LATTER : BasicTimeZone.LOCAL_FORMER;
+ LocalOption nonExistingTimeOpt = (skippedWallTime == WALLTIME_FIRST) ? LocalOption.LATTER : LocalOption.FORMER;
+ LocalOption duplicatedTimeOpt = (repeatedWallTime == WALLTIME_FIRST) ? LocalOption.FORMER : LocalOption.LATTER;
((BasicTimeZone)zone).getOffsetFromLocal(wall, nonExistingTimeOpt, duplicatedTimeOpt, offsets);
} else {
// By default, TimeZone#getOffset behaves WALLTIME_LAST for both.
@@ -5778,8 +5779,8 @@
int[] offsets = new int[2];
long wall = millis + millisInDay;
if (zone instanceof BasicTimeZone) {
- int duplicatedTimeOpt = (repeatedWallTime == WALLTIME_FIRST) ? BasicTimeZone.LOCAL_FORMER : BasicTimeZone.LOCAL_LATTER;
- int nonExistingTimeOpt = (skippedWallTime == WALLTIME_FIRST) ? BasicTimeZone.LOCAL_LATTER : BasicTimeZone.LOCAL_FORMER;
+ LocalOption nonExistingTimeOpt = (skippedWallTime == WALLTIME_FIRST) ? LocalOption.LATTER : LocalOption.FORMER;
+ LocalOption duplicatedTimeOpt = (repeatedWallTime == WALLTIME_FIRST) ? LocalOption.FORMER : LocalOption.LATTER;
((BasicTimeZone)zone).getOffsetFromLocal(wall, nonExistingTimeOpt, duplicatedTimeOpt, offsets);
} else {
// By default, TimeZone#getOffset behaves WALLTIME_LAST for both.
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/RuleBasedTimeZone.java b/icu4j/main/classes/core/src/com/ibm/icu/util/RuleBasedTimeZone.java
index 5e1d35a..6671562 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/util/RuleBasedTimeZone.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/util/RuleBasedTimeZone.java
@@ -17,9 +17,9 @@
/**
* <code>RuleBasedTimeZone</code> is a concrete subclass of <code>TimeZone</code> that allows users to define
* custom historic time transition rules.
- *
+ *
* @see com.ibm.icu.util.TimeZoneRule
- *
+ *
* @stable ICU 3.8
*/
public class RuleBasedTimeZone extends BasicTimeZone {
@@ -36,10 +36,10 @@
/**
* Constructs a <code>RuleBasedTimeZone</code> object with the ID and the
* <code>InitialTimeZoneRule</code>
- *
+ *
* @param id The time zone ID.
* @param initialRule The initial time zone rule.
- *
+ *
* @stable ICU 3.8
*/
public RuleBasedTimeZone(String id, InitialTimeZoneRule initialRule) {
@@ -52,9 +52,9 @@
* The <code>TimeZoneRule</code> must have start times, that is, the result
* of {@link com.ibm.icu.util.TimeZoneRule#isTransitionRule()} must be true.
* Otherwise, <code>IllegalArgumentException</code> is thrown.
- *
+ *
* @param rule The <code>TimeZoneRule</code>.
- *
+ *
* @stable ICU 3.8
*/
public void addTransitionRule(TimeZoneRule rule) {
@@ -77,9 +77,9 @@
throw new IllegalStateException("Too many final rules");
}
} else {
- // If this is not a final rule, add it to the historic rule list
+ // If this is not a final rule, add it to the historic rule list
if (historicRules == null) {
- historicRules = new ArrayList<TimeZoneRule>();
+ historicRules = new ArrayList<>();
}
historicRules.add(rule);
}
@@ -90,7 +90,7 @@
/**
* {@inheritDoc}
- *
+ *
* @stable ICU 3.8
*/
@Override
@@ -108,7 +108,7 @@
/**
* {@inheritDoc}
- *
+ *
* @stable ICU 3.8
*/
@Override
@@ -118,19 +118,20 @@
/**
* {@inheritDoc}
- * @internal
- * @deprecated This API is ICU internal only.
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
*/
- @Deprecated
@Override
public void getOffsetFromLocal(long date,
- int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) {
- getOffset(date, true, nonExistingTimeOpt, duplicatedTimeOpt, offsets);
+ LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets) {
+ int nonExistingTimeOptVal = getLocalOptionValue(nonExistingTimeOpt);
+ int duplicatedTimeOptVal = getLocalOptionValue(duplicatedTimeOpt);
+ getOffset(date, true, nonExistingTimeOptVal, duplicatedTimeOptVal, offsets);
}
-
+
/**
* {@inheritDoc}
- *
+ *
* @stable ICU 3.8
*/
@Override
@@ -145,7 +146,7 @@
/**
* {@inheritDoc}
- *
+ *
* @stable ICU 3.8
*/
@Override
@@ -157,7 +158,7 @@
/**
* {@inheritDoc}
- *
+ *
* @stable ICU 3.8
*/
@Override
@@ -170,7 +171,7 @@
/**
* {@inheritDoc}
- *
+ *
* @stable ICU 3.8
*/
@Override
@@ -238,7 +239,7 @@
/**
* {@inheritDoc}
- *
+ *
* @stable ICU 3.8
*/
@Override
@@ -267,7 +268,7 @@
if (finalRules[i] != null && otherRBTZ.finalRules[i] != null
&& finalRules[i].isEquivalentTo(otherRBTZ.finalRules[i])) {
continue;
-
+
}
return false;
}
@@ -302,7 +303,7 @@
/**
* {@inheritDoc}
- *
+ *
* @stable ICU 3.8
*/
@Override
@@ -321,7 +322,7 @@
}
TimeZoneRule[] rules = new TimeZoneRule[size];
rules[0] = initialRule;
-
+
int idx = 1;
if (historicRules != null) {
for (; idx < historicRules.size() + 1; idx++) {
@@ -339,7 +340,7 @@
/**
* {@inheritDoc}
- *
+ *
* @stable ICU 3.8
*/
@Override
@@ -355,7 +356,7 @@
if (tt > base || (inclusive && tt == base)) {
result = tzt;
} else {
- int idx = historicTransitions.size() - 1;
+ int idx = historicTransitions.size() - 1;
tzt = historicTransitions.get(idx);
tt = tzt.getTime();
if (inclusive && tt == base) {
@@ -411,7 +412,7 @@
/**
* {@inheritDoc}
- *
+ *
* @stable ICU 3.8
*/
@Override
@@ -428,7 +429,7 @@
} else if (tt >= base) {
return null;
} else {
- int idx = historicTransitions.size() - 1;
+ int idx = historicTransitions.size() - 1;
tzt = historicTransitions.get(idx);
tt = tzt.getTime();
if (inclusive && tt == base) {
@@ -459,7 +460,7 @@
}
idx--;
}
- result = tzt;
+ result = tzt;
}
}
// For now, this implementation ignore transitions with only zone name changes.
@@ -472,7 +473,7 @@
}
return result;
}
-
+
/**
* {@inheritDoc}
* @stable ICU 3.8
@@ -582,7 +583,7 @@
}
if (historicTransitions == null) {
- historicTransitions = new ArrayList<TimeZoneTransition>();
+ historicTransitions = new ArrayList<>();
}
historicTransitions.add(new TimeZoneTransition(nextTransitionTime, curRule, nextRule));
lastTransitionTime = nextTransitionTime;
@@ -591,7 +592,7 @@
}
if (finalRules != null) {
if (historicTransitions == null) {
- historicTransitions = new ArrayList<TimeZoneTransition>();
+ historicTransitions = new ArrayList<>();
}
// Append the first transition for each
Date d0 = finalRules[0].getNextStart(lastTransitionTime, curRule.getRawOffset(), curRule.getDSTSavings(), false);
@@ -652,7 +653,7 @@
offsets[0] = rule.getRawOffset();
offsets[1] = rule.getDSTSavings();
}
-
+
/*
* Find a time zone rule applicable to the specified time
*/
@@ -764,6 +765,7 @@
* {@inheritDoc}
* @stable ICU 49
*/
+ @Override
public boolean isFrozen() {
return isFrozen;
}
@@ -772,6 +774,7 @@
* {@inheritDoc}
* @stable ICU 49
*/
+ @Override
public TimeZone freeze() {
complete();
isFrozen = true;
@@ -782,10 +785,11 @@
* {@inheritDoc}
* @stable ICU 49
*/
+ @Override
public TimeZone cloneAsThawed() {
RuleBasedTimeZone tz = (RuleBasedTimeZone)super.cloneAsThawed();
if (historicRules != null) {
- tz.historicRules = new ArrayList<TimeZoneRule>(historicRules); // rules are immutable
+ tz.historicRules = new ArrayList<>(historicRules); // rules are immutable
}
if (finalRules != null) {
tz.finalRules = finalRules.clone();
@@ -794,4 +798,3 @@
return tz;
}
}
-
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/SimpleTimeZone.java b/icu4j/main/classes/core/src/com/ibm/icu/util/SimpleTimeZone.java
index 3779e54..ff717b3 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/util/SimpleTimeZone.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/util/SimpleTimeZone.java
@@ -790,13 +790,15 @@
/**
* {@inheritDoc}
- * @internal
- * @deprecated This API is ICU internal only.
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
*/
@Override
- @Deprecated
public void getOffsetFromLocal(long date,
- int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) {
+ LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets) {
+ int nonExistingTimeOptVal = getLocalOptionValue(nonExistingTimeOpt);
+ int duplicatedTimeOptVal = getLocalOptionValue(duplicatedTimeOpt);
+
offsets[0] = getRawOffset();
int fields[] = new int[6];
Grego.timeToFields(date, fields);
@@ -808,16 +810,16 @@
// Now, we need some adjustment
if (offsets[1] > 0) {
- if ((nonExistingTimeOpt & STD_DST_MASK) == LOCAL_STD
- || (nonExistingTimeOpt & STD_DST_MASK) != LOCAL_DST
- && (nonExistingTimeOpt & FORMER_LATTER_MASK) != LOCAL_LATTER) {
+ if ((nonExistingTimeOptVal & STD_DST_MASK) == LOCAL_STD
+ || (nonExistingTimeOptVal & STD_DST_MASK) != LOCAL_DST
+ && (nonExistingTimeOptVal & FORMER_LATTER_MASK) != LOCAL_LATTER) {
date -= getDSTSavings();
recalc = true;
}
} else {
- if ((duplicatedTimeOpt & STD_DST_MASK) == LOCAL_DST
- || (duplicatedTimeOpt & STD_DST_MASK) != LOCAL_STD
- && (duplicatedTimeOpt & FORMER_LATTER_MASK) == LOCAL_FORMER) {
+ if ((duplicatedTimeOptVal & STD_DST_MASK) == LOCAL_DST
+ || (duplicatedTimeOptVal & STD_DST_MASK) != LOCAL_STD
+ && (duplicatedTimeOptVal & FORMER_LATTER_MASK) == LOCAL_FORMER) {
date -= getDSTSavings();
recalc = true;
}
@@ -1448,4 +1450,4 @@
tz.isFrozen = false;
return tz;
}
-}
+}
\ No newline at end of file
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/VTimeZone.java b/icu4j/main/classes/core/src/com/ibm/icu/util/VTimeZone.java
index 0282754..c616de8 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/util/VTimeZone.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/util/VTimeZone.java
@@ -28,11 +28,11 @@
* in RFC2445 VTIMEZONE format. Also, you can create a <code>VTimeZone</code> instance
* from RFC2445 VTIMEZONE data stream, which allows you to calculate time
* zone offset by the rules defined by the data.<br><br>
- *
+ *
* Note: The consumer of this class reading or writing VTIMEZONE data is responsible to
* decode or encode Non-ASCII text. Methods reading/writing VTIMEZONE data in this class
* do nothing with MIME encoding.
- *
+ *
* @stable ICU 3.8
*/
public class VTimeZone extends BasicTimeZone {
@@ -41,11 +41,11 @@
/**
* Create a <code>VTimeZone</code> instance by the time zone ID.
- *
+ *
* @param tzid The time zone ID, such as America/New_York
* @return A <code>VTimeZone</code> initialized by the time zone ID, or null
* when the ID is unknown.
- *
+ *
* @stable ICU 3.8
*/
public static VTimeZone create(String tzid) {
@@ -59,14 +59,14 @@
return vtz;
}
-
+
/**
* Create a <code>VTimeZone</code> instance by RFC2445 VTIMEZONE data.
- *
+ *
* @param reader The Reader for VTIMEZONE data input stream
* @return A <code>VTimeZone</code> initialized by the VTIMEZONE data or
* null if failed to load the rule from the VTIMEZONE data.
- *
+ *
* @stable ICU 3.8
*/
public static VTimeZone create(Reader reader) {
@@ -98,13 +98,12 @@
/**
* {@inheritDoc}
- * @internal
- * @deprecated This API is ICU internal only.
+ * @draft ICU 69
+ * @provisional This API might change or be removed in a future release.
*/
- @Deprecated
@Override
public void getOffsetFromLocal(long date,
- int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets) {
+ LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets) {
tz.getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, offsets);
}
@@ -175,9 +174,9 @@
* Gets the RFC2445 TZURL property value. When a <code>VTimeZone</code> instance was created from
* VTIMEZONE data, the value is set by the TZURL property value in the data. Otherwise,
* the initial value is null.
- *
+ *
* @return The RFC2445 TZURL property value
- *
+ *
* @stable ICU 3.8
*/
public String getTZURL() {
@@ -186,9 +185,9 @@
/**
* Sets the RFC2445 TZURL property value.
- *
+ *
* @param url The TZURL property value.
- *
+ *
* @stable ICU 3.8
*/
public void setTZURL(String url) {
@@ -202,9 +201,9 @@
* Gets the RFC2445 LAST-MODIFIED property value. When a <code>VTimeZone</code> instance was created
* from VTIMEZONE data, the value is set by the LAST-MODIFIED property value in the data.
* Otherwise, the initial value is null.
- *
+ *
* @return The Date represents the RFC2445 LAST-MODIFIED date.
- *
+ *
* @stable ICU 3.8
*/
public Date getLastModified() {
@@ -213,9 +212,9 @@
/**
* Sets the date used for RFC2445 LAST-MODIFIED property value.
- *
+ *
* @param date The <code>Date</code> object represents the date for RFC2445 LAST-MODIFIED property value.
- *
+ *
* @stable ICU 3.8
*/
public void setLastModified(Date date) {
@@ -227,10 +226,10 @@
/**
* Writes RFC2445 VTIMEZONE data for this time zone
- *
+ *
* @param writer A <code>Writer</code> used for the output
* @throws IOException If there were problems creating a buffered writer or writing to it.
- *
+ *
* @stable ICU 3.8
*/
public void write(Writer writer) throws IOException {
@@ -270,12 +269,12 @@
/**
* Writes RFC2445 VTIMEZONE data applicable for dates after
* the specified start time.
- *
+ *
* @param writer The <code>Writer</code> used for the output
* @param start The start time
- *
+ *
* @throws IOException If there were problems reading and writing to the writer.
- *
+ *
* @stable ICU 3.8
*/
public void write(Writer writer, long start) throws IOException {
@@ -290,7 +289,7 @@
String[] customProperties = null;
if (olsonzid != null && ICU_TZVERSION != null) {
customProperties = new String[1];
- customProperties[0] = ICU_TZINFO_PROP + COLON + olsonzid + "[" + ICU_TZVERSION +
+ customProperties[0] = ICU_TZINFO_PROP + COLON + olsonzid + "[" + ICU_TZVERSION +
"/Partial@" + start + "]";
}
writeZone(writer, rbtz, customProperties);
@@ -304,12 +303,12 @@
* the VTIMEZONE data which can be handled these implementations. The rules
* produced by this method can be used only for calculating time zone offset
* around the specified date.
- *
+ *
* @param writer The <code>Writer</code> used for the output
* @param time The date
- *
+ *
* @throws IOException If there were problems reading or writing to the writer.
- *
+ *
* @stable ICU 3.8
*/
public void writeSimple(Writer writer, long time) throws IOException {
@@ -324,7 +323,7 @@
String[] customProperties = null;
if (olsonzid != null && ICU_TZVERSION != null) {
customProperties = new String[1];
- customProperties[0] = ICU_TZINFO_PROP + COLON + olsonzid + "[" + ICU_TZVERSION +
+ customProperties[0] = ICU_TZINFO_PROP + COLON + olsonzid + "[" + ICU_TZVERSION +
"/Simple@" + time + "]";
}
writeZone(writer, rbtz, customProperties);
@@ -405,7 +404,7 @@
// Default DST savings
private static final int DEF_DSTSAVINGS = 60*60*1000; // 1 hour
-
+
// Default time start
private static final long DEF_TZSTARTTIME = 0;
@@ -445,7 +444,7 @@
private static final String ICAL_BYDAY = "BYDAY";
private static final String ICAL_BYMONTHDAY = "BYMONTHDAY";
- private static final String[] ICAL_DOW_NAMES =
+ private static final String[] ICAL_DOW_NAMES =
{"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
// Month length in regular year
@@ -461,7 +460,7 @@
///CLOVER:ON
}
}
-
+
/* Hide the constructor */
private VTimeZone() {
}
@@ -483,7 +482,7 @@
private boolean load(Reader reader) {
// Read VTIMEZONE block into string array
try {
- vtzlines = new LinkedList<String>();
+ vtzlines = new LinkedList<>();
boolean eol = false;
boolean start = false;
boolean success = false;
@@ -578,7 +577,7 @@
String dtstart = null; // current zone starts
boolean isRRULE = false; // true if the rule is described by RRULE
List<String> dates = null; // list of RDATE or RRULE strings
- List<TimeZoneRule> rules = new ArrayList<TimeZoneRule>(); // rule list
+ List<TimeZoneRule> rules = new ArrayList<>(); // rule list
int initialRawOffset = 0; // initial offset
int initialDSTSavings = 0; // initial offset
long firstStart = MAX_TIME; // the earliest rule start time
@@ -649,7 +648,7 @@
break;
}
if (dates == null) {
- dates = new LinkedList<String>();
+ dates = new LinkedList<>();
}
// RDATE value may contain multiple date delimited
// by comma
@@ -664,7 +663,7 @@
state = ERR;
break;
} else if (dates == null) {
- dates = new LinkedList<String>();
+ dates = new LinkedList<>();
}
isRRULE = true;
dates.add(value);
@@ -699,7 +698,7 @@
} else {
// This is rare case.. just use 1 hour DST savings
rawOffset = toOffset - DEF_DSTSAVINGS;
- dstSavings = DEF_DSTSAVINGS;
+ dstSavings = DEF_DSTSAVINGS;
}
} else {
rawOffset = toOffset;
@@ -797,7 +796,7 @@
AnnualTimeZoneRule finalRule = (AnnualTimeZoneRule)rules.get(finalRuleIdx);
int tmpRaw = finalRule.getRawOffset();
int tmpDST = finalRule.getDSTSavings();
-
+
// Find the last non-final rule
Date finalStart = finalRule.getFirstStart(initialRawOffset, initialDSTSavings);
Date start = finalStart;
@@ -953,7 +952,7 @@
if (unt[0] > until[0]) {
until = unt;
}
-
+
// Check if BYMONTH + BYMONTHDAY + BYDAY rule
if (fields[0] == -1 || fields[1] == 0 || fields[3] == 0) {
return null;
@@ -1050,18 +1049,18 @@
/*
* Parse individual RRULE
- *
+ *
* On return -
- *
+ *
* int[0] month calculated by BYMONTH - 1, or -1 when not found
* int[1] day of week in BYDAY, or 0 when not found
* int[2] day of week ordinal number in BYDAY, or 0 when not found
* int[i >= 3] day of month, which could be multiple values, or 0 when not found
- *
+ *
* or
- *
+ *
* null on any error cases, for exmaple, FREQ=YEARLY is not available
- *
+ *
* When UNTIL attribute is available, the time will be set to until[0],
* otherwise, MIN_TIME
*/
@@ -1094,7 +1093,7 @@
yearly = true;
} else {
parseError = true;
- break;
+ break;
}
} else if (attr.equals(ICAL_UNTIL)) {
// ISO8601 UTC format, for example, "20060315T020000Z"
@@ -1214,7 +1213,7 @@
results[2] = nthDayOfWeek;
return results;
}
-
+
/*
* Create a TimeZoneRule by the RDATE definition
*/
@@ -1335,7 +1334,7 @@
dstMonth, dstWeekInMonth, dstDayOfWeek, dstStartTime, dstUntilTime);
}
}
- }
+ }
if (!sameRule) {
// Reset this DST information
dstName = name;
@@ -1407,7 +1406,7 @@
int offset = basictz.getOffset(0 /* any time */);
boolean isDst = (offset != basictz.getRawOffset());
writeZonePropsByTime(w, isDst, getDefaultTZName(basictz.getID(), isDst),
- offset, offset, DEF_TZSTARTTIME - offset, false);
+ offset, offset, DEF_TZSTARTTIME - offset, false);
} else {
if (dstCount > 0) {
if (finalDstRule == null) {
@@ -1474,12 +1473,12 @@
if (nextStart != null) {
writeFinalRule(w, false, finalStdRule,
stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, nextStart.getTime());
-
+
}
}
}
}
- }
+ }
}
writeFooter(w);
}
@@ -1599,7 +1598,7 @@
// Check if all days are in the same month
int startDay = dayOfMonth;
int currentMonthDays = 7;
-
+
if (dayOfMonth <= 0) {
// The start day is in previous month
int prevMonthDays = 1 - dayOfMonth;
@@ -1621,14 +1620,14 @@
currentMonthDays -= nextMonthDays;
int nextMonth = (month + 1) > 11 ? 0 : month + 1;
-
+
writeZonePropsByDOW_GEQ_DOM_sub(writer, nextMonth, 1, dayOfWeek, nextMonthDays, MAX_TIME /* Do not use UNTIL */, fromOffset);
}
writeZonePropsByDOW_GEQ_DOM_sub(writer, month, startDay, dayOfWeek, currentMonthDays, untilTime, fromOffset);
endZoneProps(writer, isDst);
}
}
-
+
/*
* Called from writeZonePropsByDOW_GEQ_DOM
*/
@@ -1829,12 +1828,12 @@
writer.write(COLON);
writer.write(tzname);
writer.write(NEWLINE);
-
+
// DTSTART
writer.write(ICAL_DTSTART);
writer.write(COLON);
writer.write(getDateTimeString(startTime + fromOffset));
- writer.write(NEWLINE);
+ writer.write(NEWLINE);
}
/*
@@ -1933,7 +1932,7 @@
int min = t / Grego.MILLIS_PER_MINUTE;
t %= Grego.MILLIS_PER_MINUTE;
int sec = t / Grego.MILLIS_PER_SECOND;
-
+
sb.append(numToString(hour, 2));
sb.append(numToString(min, 2));
sb.append(numToString(sec, 2));
@@ -2107,6 +2106,7 @@
* {@inheritDoc}
* @stable ICU 49
*/
+ @Override
public boolean isFrozen() {
return isFrozen;
}
@@ -2115,6 +2115,7 @@
* {@inheritDoc}
* @stable ICU 49
*/
+ @Override
public TimeZone freeze() {
isFrozen = true;
return this;
@@ -2124,6 +2125,7 @@
* {@inheritDoc}
* @stable ICU 49
*/
+ @Override
public TimeZone cloneAsThawed() {
VTimeZone vtz = (VTimeZone)super.cloneAsThawed();
vtz.tz = (BasicTimeZone)tz.cloneAsThawed();
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneOffsetLocalTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneOffsetLocalTest.java
index 6b8d981..55acc68 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneOffsetLocalTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneOffsetLocalTest.java
@@ -18,6 +18,7 @@
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.util.AnnualTimeZoneRule;
import com.ibm.icu.util.BasicTimeZone;
+import com.ibm.icu.util.BasicTimeZone.LocalOption;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.DateTimeRule;
import com.ibm.icu.util.GregorianCalendar;
@@ -71,8 +72,8 @@
// Expected offsets by getOffset(long time, boolean local, int[] offsets) with local = true
- // or getOffsetFromLocal(long time, int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets)
- // with nonExistingTimeOpt = LOCAL_STD/duplicatedTimeOpt = LOCAL_STD
+ // or getOffsetFromLocal(long time, LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets)
+ // with nonExistingTimeOpt = STANDARD_*/duplicatedTimeOpt = STANDARD_*
int[][] OFFSETS2 = {
// April 2, 2006
{-8*HOUR, 0},
@@ -89,8 +90,8 @@
{-8*HOUR, 0},
};
- // Expected offsets by getOffsetFromLocal(long time, int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets)
- // with nonExistingTimeOpt = LOCAL_DST/duplicatedTimeOpt = LOCAL_DST
+ // Expected offsets by getOffsetFromLocal(long time, LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets)
+ // with nonExistingTimeOpt = DAYLIGHT_*/duplicatedTimeOpt = DAYLIGHT_*
int[][] OFFSETS3 = {
// April 2, 2006
{-8*HOUR, 0},
@@ -184,39 +185,39 @@
}
}
- // Test getOffsetFromLocal(long time, int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets)
- // with nonExistingTimeOpt = LOCAL_STD/duplicatedTimeOpt = LOCAL_STD
+ // Test getOffsetFromLocal(long time, LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets)
+ // with nonExistingTimeOpt = STANDARD_*/duplicatedTimeOpt = STANDARD_*
for (int i = 0; i < TESTZONES.length; i++) {
for (int m = 0; m < MILLIS.length; m++) {
- TESTZONES[i].getOffsetFromLocal(MILLIS[m], BasicTimeZone.LOCAL_STD, BasicTimeZone.LOCAL_STD, offsets);
+ TESTZONES[i].getOffsetFromLocal(MILLIS[m], LocalOption.STANDARD_FORMER, LocalOption.STANDARD_LATTER, offsets);
if (offsets[0] != OFFSETS2[m][0] || offsets[1] != OFFSETS2[m][1]) {
errln("Bad offset returned by " + TESTZONES[i].getID() + " at "
- + df.format(new Date(MILLIS[m])) + "(wall/STD/STD) - Got: "
+ + df.format(new Date(MILLIS[m])) + "(wall/STANDARD_FORMER/STANDARD_LATTER) - Got: "
+ offsets[0] + "/" + offsets[1]
+ " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
}
}
}
- // Test getOffsetFromLocal(long time, int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets)
- // with nonExistingTimeOpt = LOCAL_DST/duplicatedTimeOpt = LOCAL_DST
+ // Test getOffsetFromLocal(long time, LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets)
+ // with nonExistingTimeOpt = DAYLIGHT_*/duplicatedTimeOpt = DAYLIGHT_*
for (int i = 0; i < TESTZONES.length; i++) {
for (int m = 0; m < MILLIS.length; m++) {
- TESTZONES[i].getOffsetFromLocal(MILLIS[m], BasicTimeZone.LOCAL_DST, BasicTimeZone.LOCAL_DST, offsets);
+ TESTZONES[i].getOffsetFromLocal(MILLIS[m], LocalOption.DAYLIGHT_LATTER, LocalOption.DAYLIGHT_FORMER, offsets);
if (offsets[0] != OFFSETS3[m][0] || offsets[1] != OFFSETS3[m][1]) {
errln("Bad offset returned by " + TESTZONES[i].getID() + " at "
- + df.format(new Date(MILLIS[m])) + "(wall/DST/DST) - Got: "
+ + df.format(new Date(MILLIS[m])) + "(wall/DAYLIGHT_LATTER/DAYLIGHT_FORMER) - Got: "
+ offsets[0] + "/" + offsets[1]
+ " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]);
}
}
}
- // Test getOffsetFromLocal(long time, int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets)
- // with nonExistingTimeOpt = LOCAL_FORMER/duplicatedTimeOpt = LOCAL_LATTER
+ // Test getOffsetFromLocal(long time, LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets)
+ // with nonExistingTimeOpt = FORMER/duplicatedTimeOpt = LATTER
for (int i = 0; i < TESTZONES.length; i++) {
for (int m = 0; m < MILLIS.length; m++) {
- TESTZONES[i].getOffsetFromLocal(MILLIS[m], BasicTimeZone.LOCAL_FORMER, BasicTimeZone.LOCAL_LATTER, offsets);
+ TESTZONES[i].getOffsetFromLocal(MILLIS[m], LocalOption.FORMER, LocalOption.LATTER, offsets);
if (offsets[0] != OFFSETS2[m][0] || offsets[1] != OFFSETS2[m][1]) {
errln("Bad offset returned by " + TESTZONES[i].getID() + " at "
+ df.format(new Date(MILLIS[m])) + "(wall/FORMER/LATTER) - Got: "
@@ -226,11 +227,11 @@
}
}
- // Test getOffsetFromLocal(long time, int nonExistingTimeOpt, int duplicatedTimeOpt, int[] offsets)
- // with nonExistingTimeOpt = LOCAL_LATTER/duplicatedTimeOpt = LOCAL_FORMER
+ // Test getOffsetFromLocal(long time, LocalOption nonExistingTimeOpt, LocalOption duplicatedTimeOpt, int[] offsets)
+ // with nonExistingTimeOpt = LATTER/duplicatedTimeOpt = FORMER
for (int i = 0; i < TESTZONES.length; i++) {
for (int m = 0; m < MILLIS.length; m++) {
- TESTZONES[i].getOffsetFromLocal(MILLIS[m], BasicTimeZone.LOCAL_LATTER, BasicTimeZone.LOCAL_FORMER, offsets);
+ TESTZONES[i].getOffsetFromLocal(MILLIS[m], LocalOption.LATTER, LocalOption.FORMER, offsets);
if (offsets[0] != OFFSETS3[m][0] || offsets[1] != OFFSETS3[m][1]) {
errln("Bad offset returned by " + TESTZONES[i].getID() + " at "
+ df.format(new Date(MILLIS[m])) + "(wall/LATTER/FORMER) - Got: "
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneRuleTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneRuleTest.java
index 34c4e3b..08df3fb 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneRuleTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneRuleTest.java
@@ -24,6 +24,7 @@
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.util.AnnualTimeZoneRule;
import com.ibm.icu.util.BasicTimeZone;
+import com.ibm.icu.util.BasicTimeZone.LocalOption;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.DateTimeRule;
import com.ibm.icu.util.GregorianCalendar;
@@ -1235,7 +1236,7 @@
int[] offsets_vtzc = new int[2];
VTimeZone vtzc = VTimeZone.create("PST");
- vtzc.getOffsetFromLocal(Calendar.getInstance(vtzc).getTimeInMillis(), VTimeZone.LOCAL_STD, VTimeZone.LOCAL_STD, offsets_vtzc);
+ vtzc.getOffsetFromLocal(Calendar.getInstance(vtzc).getTimeInMillis(), LocalOption.STANDARD_FORMER, LocalOption.STANDARD_LATTER, offsets_vtzc);
if (offsets_vtzc[0] > offsets_vtzc[1]) {
errln("Error getOffsetFromLocal()");
}
@@ -1469,7 +1470,7 @@
BasicTimeZone btz = (BasicTimeZone)tz;
int []offsets = new int[2];
- btz.getOffsetFromLocal(Calendar.getInstance().getTimeInMillis(), BasicTimeZone.LOCAL_STD, BasicTimeZone.LOCAL_STD, offsets);
+ btz.getOffsetFromLocal(Calendar.getInstance().getTimeInMillis(), LocalOption.STANDARD_FORMER, LocalOption.STANDARD_LATTER, offsets);
if (offsets[0] > offsets[1]) {
errln("Error calling getOffsetFromLocal().");
}