use of android.icu.util.BasicTimeZone in project j2objc by google.
the class IcuZoneRulesProviderTest method testTransitionsNearInstants.
/**
* Verifies that ICU and java.time return the same transitions before and after a pre-selected
* set of instants in time.
*/
@Test
public void testTransitionsNearInstants() {
// An arbitrary set of instants at which to test the offsets in both implementations.
Instant[] instants = new Instant[] { LocalDateTime.of(1900, Month.DECEMBER, 24, 12, 0).toInstant(ZoneOffset.UTC), LocalDateTime.of(1970, Month.JANUARY, 1, 2, 3).toInstant(ZoneOffset.UTC), LocalDateTime.of(1980, Month.FEBRUARY, 4, 5, 6).toInstant(ZoneOffset.UTC), LocalDateTime.of(1990, Month.MARCH, 7, 8, 9).toInstant(ZoneOffset.UTC), LocalDateTime.of(2000, Month.APRIL, 10, 11, 12).toInstant(ZoneOffset.UTC), LocalDateTime.of(2016, Month.MAY, 13, 14, 15).toInstant(ZoneOffset.UTC), LocalDateTime.of(2020, Month.JUNE, 16, 17, 18).toInstant(ZoneOffset.UTC), LocalDateTime.of(2100, Month.JULY, 19, 20, 21).toInstant(ZoneOffset.UTC), // updates don't break on the then-current date.
Instant.now() };
// Coincidentally this test verifies that all zones can be converted to ZoneRules and
// don't violate any of the assumptions of IcuZoneRulesProvider.
ZoneRules rules = ZoneRulesProvider.getRules(zoneId, false);
BasicTimeZone timeZone = (BasicTimeZone) TimeZone.getTimeZone(zoneId);
int[] icuOffsets = new int[2];
for (Instant instant : instants) {
ZoneOffset offset = rules.getOffset(instant);
Duration daylightSavings = rules.getDaylightSavings(instant);
timeZone.getOffset(instant.toEpochMilli(), false, icuOffsets);
assertEquals("total offset for " + zoneId + " at " + instant, icuOffsets[1] + icuOffsets[0], offset.getTotalSeconds() * 1000);
assertEquals("dst offset for " + zoneId + " at " + instant, icuOffsets[1], daylightSavings.toMillis());
ZoneOffsetTransition jtTrans;
TimeZoneTransition icuTrans;
jtTrans = rules.nextTransition(instant);
icuTrans = timeZone.getNextTransition(instant.toEpochMilli(), false);
while (isIcuOnlyTransition(icuTrans)) {
icuTrans = timeZone.getNextTransition(icuTrans.getTime(), false);
}
assertEquivalent(icuTrans, jtTrans);
jtTrans = rules.previousTransition(instant);
icuTrans = timeZone.getPreviousTransition(instant.toEpochMilli(), false);
// Find previous "real" transition.
while (isIcuOnlyTransition(icuTrans)) {
icuTrans = timeZone.getPreviousTransition(icuTrans.getTime(), false);
}
assertEquivalent(icuTrans, jtTrans);
}
}
use of android.icu.util.BasicTimeZone in project j2objc by google.
the class IcuZoneRulesProviderTest method testAllTransitions.
/**
* Verifies that ICU and java.time rules return the same transitions between 1900 and 2100.
*/
@Test
public void testAllTransitions() {
final Instant start = LocalDateTime.of(1900, Month.JANUARY, 1, 12, 0).toInstant(ZoneOffset.UTC);
// Many timezones have ongoing DST changes, so they would generate transitions endlessly.
// Pick a far-future end date to stop comparing in that case.
final Instant end = LocalDateTime.of(2100, Month.DECEMBER, 31, 12, 0).toInstant(ZoneOffset.UTC);
ZoneRules rules = ZoneRulesProvider.getRules(zoneId, false);
BasicTimeZone timeZone = (BasicTimeZone) TimeZone.getTimeZone(zoneId);
Instant instant = start;
while (instant.isBefore(end)) {
ZoneOffsetTransition jtTrans;
TimeZoneTransition icuTrans;
jtTrans = rules.nextTransition(instant);
icuTrans = timeZone.getNextTransition(instant.toEpochMilli(), false);
while (isIcuOnlyTransition(icuTrans)) {
icuTrans = timeZone.getNextTransition(icuTrans.getTime(), false);
}
assertEquivalent(icuTrans, jtTrans);
if (jtTrans == null) {
break;
}
instant = jtTrans.getInstant();
}
}
use of android.icu.util.BasicTimeZone in project j2objc by google.
the class IcuZoneRulesProvider method generateZoneRules.
/*
* This implementation is only tested with BasicTimeZone objects and depends on
* implementation details of that class:
*
* 0. TimeZone.getFrozenTimeZone() always returns a BasicTimeZone object.
* 1. The first rule is always an InitialTimeZoneRule (guaranteed by spec).
* 2. AnnualTimeZoneRules are only used as "final rules".
* 3. The final rules are either 0 or 2 AnnualTimeZoneRules
* 4. The final rules have endYear set to MAX_YEAR.
* 5. Each transition generated by the rules changes either the raw offset, the total offset
* or both.
* 6. There is a non-immense number of transitions for any rule before the final rules apply
* (enforced via the arbitrary limit defined in MAX_TRANSITIONS).
*
* Assumptions #5 and #6 are not strictly required for this code to work, but hold for the
* the data and code at the time of implementation. If they were broken they would indicate
* an incomplete understanding of how ICU TimeZoneRules are used which would probably mean that
* this code needs to be updated.
*
* These assumptions are verified using the verify() method where appropriate.
*/
static ZoneRules generateZoneRules(String zoneId) {
TimeZone timeZone = TimeZone.getFrozenTimeZone(zoneId);
// Assumption #0
verify(timeZone instanceof BasicTimeZone, zoneId, "Unexpected time zone class " + timeZone.getClass());
BasicTimeZone tz = (BasicTimeZone) timeZone;
TimeZoneRule[] rules = tz.getTimeZoneRules();
// Assumption #1
InitialTimeZoneRule initial = (InitialTimeZoneRule) rules[0];
ZoneOffset baseStandardOffset = millisToOffset(initial.getRawOffset());
ZoneOffset baseWallOffset = millisToOffset((initial.getRawOffset() + initial.getDSTSavings()));
List<ZoneOffsetTransition> standardOffsetTransitionList = new ArrayList<>();
List<ZoneOffsetTransition> transitionList = new ArrayList<>();
List<ZoneOffsetTransitionRule> lastRules = new ArrayList<>();
int preLastDstSavings = 0;
AnnualTimeZoneRule last1 = null;
AnnualTimeZoneRule last2 = null;
TimeZoneTransition transition = tz.getNextTransition(Long.MIN_VALUE, false);
int transitionCount = 1;
// "last rules" in java.time) the "break transitionLoop" will be used to exit the loop.
transitionLoop: while (transition != null) {
TimeZoneRule from = transition.getFrom();
TimeZoneRule to = transition.getTo();
boolean hadEffect = false;
if (from.getRawOffset() != to.getRawOffset()) {
standardOffsetTransitionList.add(new ZoneOffsetTransition(TimeUnit.MILLISECONDS.toSeconds(transition.getTime()), millisToOffset(from.getRawOffset()), millisToOffset(to.getRawOffset())));
hadEffect = true;
}
int fromTotalOffset = from.getRawOffset() + from.getDSTSavings();
int toTotalOffset = to.getRawOffset() + to.getDSTSavings();
if (fromTotalOffset != toTotalOffset) {
transitionList.add(new ZoneOffsetTransition(TimeUnit.MILLISECONDS.toSeconds(transition.getTime()), millisToOffset(fromTotalOffset), millisToOffset(toTotalOffset)));
hadEffect = true;
}
// Assumption #5
verify(hadEffect, zoneId, "Transition changed neither total nor raw offset.");
if (to instanceof AnnualTimeZoneRule) {
// The presence of an AnnualTimeZoneRule is taken as an indication of a final rule.
if (last1 == null) {
preLastDstSavings = from.getDSTSavings();
last1 = (AnnualTimeZoneRule) to;
// Assumption #4
verify(last1.getEndYear() == AnnualTimeZoneRule.MAX_YEAR, zoneId, "AnnualTimeZoneRule is not permanent.");
} else {
last2 = (AnnualTimeZoneRule) to;
// Assumption #4
verify(last2.getEndYear() == AnnualTimeZoneRule.MAX_YEAR, zoneId, "AnnualTimeZoneRule is not permanent.");
// Assumption #3
transition = tz.getNextTransition(transition.getTime(), false);
verify(transition.getTo() == last1, zoneId, "Unexpected rule after 2 AnnualTimeZoneRules.");
break transitionLoop;
}
} else {
// Assumption #2
verify(last1 == null, zoneId, "Unexpected rule after AnnualTimeZoneRule.");
}
verify(transitionCount <= MAX_TRANSITIONS, zoneId, "More than " + MAX_TRANSITIONS + " transitions.");
transition = tz.getNextTransition(transition.getTime(), false);
transitionCount++;
}
if (last1 != null) {
// Assumption #3
verify(last2 != null, zoneId, "Only one AnnualTimeZoneRule.");
lastRules.add(toZoneOffsetTransitionRule(last1, preLastDstSavings));
lastRules.add(toZoneOffsetTransitionRule(last2, last1.getDSTSavings()));
}
return ZoneRules.of(baseStandardOffset, baseWallOffset, standardOffsetTransitionList, transitionList, lastRules);
}
Aggregations