mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
java.time: add support for time zones
This commit is contained in:
parent
81878548b4
commit
2924af963d
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.impl.tz;
|
package org.teavm.classlib.impl.tz;
|
||||||
|
|
||||||
|
import java.time.zone.ZoneRules;
|
||||||
import org.teavm.classlib.impl.Base46;
|
import org.teavm.classlib.impl.Base46;
|
||||||
|
|
||||||
public class AliasDateTimeZone extends StorableDateTimeZone {
|
public class AliasDateTimeZone extends StorableDateTimeZone {
|
||||||
|
@ -55,4 +56,9 @@ public class AliasDateTimeZone extends StorableDateTimeZone {
|
||||||
Base46.encodeUnsigned(sb, ALIAS);
|
Base46.encodeUnsigned(sb, ALIAS);
|
||||||
sb.append(innerZone.getID());
|
sb.append(innerZone.getID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZoneRules asZoneRules() {
|
||||||
|
return innerZone.asZoneRules();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.impl.tz;
|
package org.teavm.classlib.impl.tz;
|
||||||
|
|
||||||
|
import java.time.zone.ZoneRules;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Improves the performance of requesting time zone offsets and name keys by
|
* Improves the performance of requesting time zone offsets and name keys by
|
||||||
* caching the results. Time zones that have simple rules or are fixed should
|
* caching the results. Time zones that have simple rules or are fixed should
|
||||||
|
@ -97,6 +99,11 @@ public final class CachedDateTimeZone extends StorableDateTimeZone {
|
||||||
return iZone.previousTransition(instant);
|
return iZone.previousTransition(instant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZoneRules asZoneRules() {
|
||||||
|
return iZone.asZoneRules();
|
||||||
|
}
|
||||||
|
|
||||||
// Although accessed by multiple threads, this method doesn't need to be
|
// Although accessed by multiple threads, this method doesn't need to be
|
||||||
// synchronized.
|
// synchronized.
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.impl.tz;
|
package org.teavm.classlib.impl.tz;
|
||||||
|
|
||||||
|
import java.time.zone.ZoneRules;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DateTimeZone represents a time zone.
|
* DateTimeZone represents a time zone.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -485,4 +487,6 @@ public abstract class DateTimeZone {
|
||||||
* @return milliseconds from 1970-01-01T00:00:00Z
|
* @return milliseconds from 1970-01-01T00:00:00Z
|
||||||
*/
|
*/
|
||||||
public abstract long previousTransition(long instant);
|
public abstract long previousTransition(long instant);
|
||||||
|
|
||||||
|
public abstract ZoneRules asZoneRules();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,14 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.impl.tz;
|
package org.teavm.classlib.impl.tz;
|
||||||
|
|
||||||
|
import java.time.DayOfWeek;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.Month;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.zone.ZoneOffsetTransition;
|
||||||
|
import java.time.zone.ZoneOffsetTransitionRule;
|
||||||
|
import java.time.zone.ZoneRules;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.teavm.classlib.impl.Base46;
|
import org.teavm.classlib.impl.Base46;
|
||||||
import org.teavm.classlib.impl.CharFlow;
|
import org.teavm.classlib.impl.CharFlow;
|
||||||
|
@ -323,7 +331,7 @@ public class DateTimeZoneBuilder {
|
||||||
}
|
}
|
||||||
Base46.encodeUnsigned(sb, flags);
|
Base46.encodeUnsigned(sb, flags);
|
||||||
Base46.encodeUnsigned(sb, iMonthOfYear);
|
Base46.encodeUnsigned(sb, iMonthOfYear);
|
||||||
Base46.encodeUnsigned(sb, iDayOfMonth);
|
Base46.encode(sb, iDayOfMonth);
|
||||||
if (iDayOfWeek != 0) {
|
if (iDayOfWeek != 0) {
|
||||||
Base46.encode(sb, iDayOfWeek);
|
Base46.encode(sb, iDayOfWeek);
|
||||||
}
|
}
|
||||||
|
@ -350,7 +358,7 @@ public class DateTimeZoneBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
int monthOfYear = Base46.decodeUnsigned(flow);
|
int monthOfYear = Base46.decodeUnsigned(flow);
|
||||||
int dayOfMonth = Base46.decodeUnsigned(flow);
|
int dayOfMonth = Base46.decode(flow);
|
||||||
int dayOfWeek = hasDayOfWeek ? Base46.decode(flow) : 0;
|
int dayOfWeek = hasDayOfWeek ? Base46.decode(flow) : 0;
|
||||||
int millisOfDay = (int) StorableDateTimeZone.readUnsignedTime(flow);
|
int millisOfDay = (int) StorableDateTimeZone.readUnsignedTime(flow);
|
||||||
return new OfYear(mode, monthOfYear, dayOfMonth, dayOfWeek, advance, millisOfDay);
|
return new OfYear(mode, monthOfYear, dayOfMonth, dayOfWeek, advance, millisOfDay);
|
||||||
|
@ -1065,6 +1073,11 @@ public class DateTimeZoneBuilder {
|
||||||
Recurrence endRecurrence = Recurrence.read(flow);
|
Recurrence endRecurrence = Recurrence.read(flow);
|
||||||
return new DSTZone(id, standardOffset, startRecurrence, endRecurrence);
|
return new DSTZone(id, standardOffset, startRecurrence, endRecurrence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZoneRules asZoneRules() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class PrecalculatedZone extends StorableDateTimeZone {
|
static final class PrecalculatedZone extends StorableDateTimeZone {
|
||||||
|
@ -1350,6 +1363,117 @@ public class DateTimeZoneBuilder {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZoneRules asZoneRules() {
|
||||||
|
List<ZoneOffsetTransition> standardTransitions = new ArrayList<>();
|
||||||
|
List<ZoneOffsetTransition> transitions = new ArrayList<>();
|
||||||
|
ZoneOffset firstStandardOffset = ZoneOffset.ofTotalSeconds(iStandardOffsets[0] / 1000);
|
||||||
|
ZoneOffset firstOffset = ZoneOffset.ofTotalSeconds(iWallOffsets[0] / 1000);
|
||||||
|
ZoneOffset lastStandardOffset = firstStandardOffset;
|
||||||
|
ZoneOffset lastOffset = firstOffset;
|
||||||
|
long time = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
for (int i = 1; i < iTransitions.length; ++i) {
|
||||||
|
time = iTransitions[i];
|
||||||
|
LocalDateTime transitionTime = LocalDateTime.ofEpochSecond(time / 1000, 0, ZoneOffset.UTC);
|
||||||
|
if (iStandardOffsets[i] != iStandardOffsets[i - 1]) {
|
||||||
|
int offsetInSeconds = iStandardOffsets[i] / 1000;
|
||||||
|
int lastOffsetInSeconds = lastStandardOffset.getTotalSeconds();
|
||||||
|
ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetInSeconds);
|
||||||
|
standardTransitions.add(ZoneOffsetTransition.of(transitionTime.plusSeconds(lastOffsetInSeconds),
|
||||||
|
lastStandardOffset, offset));
|
||||||
|
lastStandardOffset = offset;
|
||||||
|
}
|
||||||
|
if (iWallOffsets[i] != iWallOffsets[i - 1]) {
|
||||||
|
ZoneOffset offset = ZoneOffset.ofTotalSeconds(iWallOffsets[i] / 1000);
|
||||||
|
int lastOffsetInSeconds = lastOffset.getTotalSeconds();
|
||||||
|
transitions.add(ZoneOffsetTransition.of(transitionTime.plusSeconds(lastOffsetInSeconds),
|
||||||
|
lastOffset, offset));
|
||||||
|
lastOffset = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ZoneOffsetTransitionRule> lastRules;
|
||||||
|
if (iTailZone != null) {
|
||||||
|
if (time != Long.MIN_VALUE) {
|
||||||
|
int count = 0;
|
||||||
|
while (count < 2) {
|
||||||
|
time = iTailZone.nextTransition(time);
|
||||||
|
LocalDateTime transitionTime = LocalDateTime.ofEpochSecond(time / 1000, 0, ZoneOffset.UTC);
|
||||||
|
int newOffset = iTailZone.getOffset(time) / 1000;
|
||||||
|
if (newOffset != lastOffset.getTotalSeconds()) {
|
||||||
|
transitions.add(ZoneOffsetTransition.of(
|
||||||
|
transitionTime.plusSeconds(lastOffset.getTotalSeconds()),
|
||||||
|
lastOffset, ZoneOffset.ofTotalSeconds(newOffset)
|
||||||
|
));
|
||||||
|
count++;
|
||||||
|
lastOffset = ZoneOffset.ofTotalSeconds(newOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZoneOffset tailStandardOffset = ZoneOffset.ofTotalSeconds(iTailZone.iStandardOffset / 1000);
|
||||||
|
ZoneOffset startRecurrenceOffset = ZoneOffset.ofTotalSeconds(
|
||||||
|
(iTailZone.iStandardOffset + iTailZone.iStartRecurrence.iSaveMillis) / 1000);
|
||||||
|
ZoneOffset endRecurrenceOffset = ZoneOffset.ofTotalSeconds(
|
||||||
|
(iTailZone.iStandardOffset + iTailZone.iEndRecurrence.iSaveMillis) / 1000);
|
||||||
|
ZoneOffsetTransitionRule firstRule = createRule(iTailZone.iStartRecurrence.iOfYear, tailStandardOffset,
|
||||||
|
endRecurrenceOffset, startRecurrenceOffset);
|
||||||
|
ZoneOffsetTransitionRule lastRule = createRule(iTailZone.iEndRecurrence.iOfYear, tailStandardOffset,
|
||||||
|
startRecurrenceOffset, endRecurrenceOffset);
|
||||||
|
lastRules = Arrays.asList(firstRule, lastRule);
|
||||||
|
} else {
|
||||||
|
lastRules = Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZoneRules.of(firstStandardOffset, firstOffset, standardTransitions, transitions, lastRules);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZoneOffsetTransitionRule createRule(OfYear ofYear, ZoneOffset standardOffset,
|
||||||
|
ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
|
||||||
|
int millisOfDay = ofYear.iMillisOfDay;
|
||||||
|
boolean midnight = false;
|
||||||
|
if (millisOfDay == 24 * 60 * 60 * 1000) {
|
||||||
|
millisOfDay = 0;
|
||||||
|
midnight = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZoneOffsetTransitionRule.TimeDefinition mode;
|
||||||
|
switch (ofYear.iMode) {
|
||||||
|
case 'u':
|
||||||
|
mode = ZoneOffsetTransitionRule.TimeDefinition.UTC;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
mode = ZoneOffsetTransitionRule.TimeDefinition.WALL;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
mode = ZoneOffsetTransitionRule.TimeDefinition.STANDARD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Month month = Month.of(ofYear.iMonthOfYear);
|
||||||
|
int dayOfMonthIndicator = ofYear.iDayOfMonth;
|
||||||
|
if (dayOfMonthIndicator < 0) {
|
||||||
|
if (month != Month.FEBRUARY) {
|
||||||
|
dayOfMonthIndicator = month.maxLength() - 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZoneOffsetTransitionRule.of(
|
||||||
|
month,
|
||||||
|
dayOfMonthIndicator,
|
||||||
|
ofYear.iDayOfWeek != 0 ? DayOfWeek.of(ofYear.iDayOfWeek) : null,
|
||||||
|
LocalTime.ofSecondOfDay(millisOfDay / 1000),
|
||||||
|
midnight,
|
||||||
|
mode,
|
||||||
|
standardOffset,
|
||||||
|
offsetBefore,
|
||||||
|
offsetAfter
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class RuleBasedZone extends StorableDateTimeZone {
|
static final class RuleBasedZone extends StorableDateTimeZone {
|
||||||
|
@ -1521,5 +1645,11 @@ public class DateTimeZoneBuilder {
|
||||||
}
|
}
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZoneRules asZoneRules() {
|
||||||
|
initZone();
|
||||||
|
return zone.asZoneRules();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.impl.tz;
|
package org.teavm.classlib.impl.tz;
|
||||||
|
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.zone.ZoneRules;
|
||||||
|
import java.util.Collections;
|
||||||
import org.teavm.classlib.impl.Base46;
|
import org.teavm.classlib.impl.Base46;
|
||||||
import org.teavm.classlib.impl.CharFlow;
|
import org.teavm.classlib.impl.CharFlow;
|
||||||
|
|
||||||
|
@ -78,4 +81,19 @@ public final class FixedDateTimeZone extends StorableDateTimeZone {
|
||||||
int standardOffset = (int) readTime(flow);
|
int standardOffset = (int) readTime(flow);
|
||||||
return new FixedDateTimeZone(id, wallOffset, standardOffset);
|
return new FixedDateTimeZone(id, wallOffset, standardOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZoneRules asZoneRules() {
|
||||||
|
if (iWallOffset == iStandardOffset) {
|
||||||
|
return ZoneRules.of(ZoneOffset.ofTotalSeconds(iStandardOffset / 1000));
|
||||||
|
} else {
|
||||||
|
return ZoneRules.of(
|
||||||
|
ZoneOffset.ofTotalSeconds(iStandardOffset / 1000),
|
||||||
|
ZoneOffset.ofTotalSeconds(iWallOffset / 1000),
|
||||||
|
Collections.emptyList(),
|
||||||
|
Collections.emptyList(),
|
||||||
|
Collections.emptyList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.threeten.bp.zone;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.NavigableMap;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import org.teavm.classlib.impl.tz.DateTimeZone;
|
||||||
|
import org.teavm.classlib.impl.tz.DateTimeZoneProvider;
|
||||||
|
|
||||||
|
class JodaRulesProvider extends ZoneRulesProvider {
|
||||||
|
private Set<String> zoneIds;
|
||||||
|
private Map<String, ZoneRules> cache = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Set<String> provideZoneIds() {
|
||||||
|
if (zoneIds == null) {
|
||||||
|
zoneIds = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(DateTimeZoneProvider.getIds())));
|
||||||
|
}
|
||||||
|
return zoneIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ZoneRules provideRules(String regionId, boolean forCaching) {
|
||||||
|
ZoneRules result = cache.get(regionId);
|
||||||
|
if (result == null) {
|
||||||
|
DateTimeZone zone = DateTimeZoneProvider.getTimeZone(regionId);
|
||||||
|
if (zone == null) {
|
||||||
|
throw new ZoneRulesException(regionId);
|
||||||
|
}
|
||||||
|
result = (ZoneRules) (Object) zone.asZoneRules();
|
||||||
|
cache.put(regionId, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
|
||||||
|
ZoneRules result = provideRules(zoneId, false);
|
||||||
|
TreeMap<String, ZoneRules> map = new TreeMap<>();
|
||||||
|
map.put("", result);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,7 +38,6 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.threeten.bp.Duration;
|
import org.threeten.bp.Duration;
|
||||||
import org.threeten.bp.Instant;
|
import org.threeten.bp.Instant;
|
||||||
import org.threeten.bp.LocalDate;
|
import org.threeten.bp.LocalDate;
|
||||||
|
@ -90,7 +89,7 @@ final class StandardZoneRules extends ZoneRules implements Serializable {
|
||||||
/**
|
/**
|
||||||
* The map of recent transitions.
|
* The map of recent transitions.
|
||||||
*/
|
*/
|
||||||
private final Map<Integer, ZoneOffsetTransition[]> lastRulesCache = new HashMap<>();
|
private final Map<Integer, ZoneOffsetTransition[]> lastRulesCache = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance.
|
* Creates an instance.
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of JSR-310 nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
package org.threeten.bp.zone;
|
|
||||||
|
|
||||||
import java.util.ServiceConfigurationError;
|
|
||||||
import java.util.ServiceLoader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controls how the time-zone rules are initialized.
|
|
||||||
* <p>
|
|
||||||
* The default behavior is to use {@link ServiceLoader} to find instances of {@link ZoneRulesProvider}.
|
|
||||||
* Use the {@link #setInitializer(ZoneRulesInitializer)} method to replace this behavior.
|
|
||||||
* The initializer instance must perform the work of creating the {@code ZoneRulesProvider} within
|
|
||||||
* the {@link #initializeProviders()} method to ensure that the provider is not initialized too early.
|
|
||||||
* <p>
|
|
||||||
* <b>The initializer must be set before class loading of any other ThreeTen-Backport class to have any effect!</b>
|
|
||||||
* <p>
|
|
||||||
* This class has been added primarily for the benefit of Android.
|
|
||||||
*/
|
|
||||||
public abstract class ZoneRulesInitializer {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An instance that does nothing.
|
|
||||||
* Call {@link #setInitializer(ZoneRulesInitializer)} with this instance to
|
|
||||||
* block the service loader search. This will leave the system with no providers.
|
|
||||||
*/
|
|
||||||
public static final ZoneRulesInitializer DO_NOTHING = new DoNothingZoneRulesInitializer();
|
|
||||||
|
|
||||||
private static boolean INITIALIZED;
|
|
||||||
private static ZoneRulesInitializer INITIALIZER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the initializer to use.
|
|
||||||
* <p>
|
|
||||||
* This can only be invoked before the {@link ZoneRulesProvider} class is loaded.
|
|
||||||
* Invoking this method at a later point will throw an exception.
|
|
||||||
*
|
|
||||||
* @param initializer the initializer to use
|
|
||||||
* @throws IllegalStateException if initialization has already occurred or another initializer has been set
|
|
||||||
*/
|
|
||||||
public static void setInitializer(ZoneRulesInitializer initializer) {
|
|
||||||
if (INITIALIZED) {
|
|
||||||
throw new IllegalStateException("Already initialized");
|
|
||||||
}
|
|
||||||
if (INITIALIZER != null) {
|
|
||||||
throw new IllegalStateException("Initializer was already set, possibly with a default during initialization");
|
|
||||||
}
|
|
||||||
INITIALIZER = initializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
// initialize the providers
|
|
||||||
static void initialize() {
|
|
||||||
if (INITIALIZED) {
|
|
||||||
throw new IllegalStateException("Already initialized");
|
|
||||||
}
|
|
||||||
INITIALIZED = true;
|
|
||||||
// Set the default initializer if none has been provided yet.
|
|
||||||
if (INITIALIZER == null) {
|
|
||||||
INITIALIZER = new ServiceLoaderZoneRulesInitializer();
|
|
||||||
}
|
|
||||||
INITIALIZER.initializeProviders();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the providers.
|
|
||||||
* <p>
|
|
||||||
* The implementation should perform whatever work is necessary to initialize the providers.
|
|
||||||
* This will result in one or more calls to {@link ZoneRulesProvider#registerProvider(ZoneRulesProvider)}.
|
|
||||||
* <p>
|
|
||||||
* It is vital that the instance of {@link ZoneRulesProvider} is not created until this method is invoked.
|
|
||||||
* <p>
|
|
||||||
* It is guaranteed that this method will be invoked once and only once.
|
|
||||||
*/
|
|
||||||
protected abstract void initializeProviders();
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Implementation that does nothing.
|
|
||||||
*/
|
|
||||||
static class DoNothingZoneRulesInitializer extends ZoneRulesInitializer {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void initializeProviders() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation that uses the service loader.
|
|
||||||
*/
|
|
||||||
static class ServiceLoaderZoneRulesInitializer extends ZoneRulesInitializer {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void initializeProviders() {
|
|
||||||
ServiceLoader<ZoneRulesProvider> loader = ServiceLoader.load(ZoneRulesProvider.class, ZoneRulesProvider.class.getClassLoader());
|
|
||||||
for (ZoneRulesProvider provider : loader) {
|
|
||||||
try {
|
|
||||||
ZoneRulesProvider.registerProvider(provider);
|
|
||||||
} catch (ServiceConfigurationError ex) {
|
|
||||||
if (!(ex.getCause() instanceof SecurityException)) {
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -79,8 +79,9 @@ public abstract class ZoneRulesProvider {
|
||||||
* The lookup from zone region ID to provider.
|
* The lookup from zone region ID to provider.
|
||||||
*/
|
*/
|
||||||
private static final Map<String, ZoneRulesProvider> ZONES = new HashMap<>();
|
private static final Map<String, ZoneRulesProvider> ZONES = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ZoneRulesInitializer.initialize();
|
registerProvider0(new JodaRulesProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
|
@ -452,12 +452,12 @@ public class TestLocalDate extends AbstractDateTimeTest {
|
||||||
assertEquals(LocalDate.ofEpochDay(minValidEpochdays), LocalDate.of(Year.MIN_VALUE, 1, 1));
|
assertEquals(LocalDate.ofEpochDay(minValidEpochdays), LocalDate.of(Year.MIN_VALUE, 1, 1));
|
||||||
|
|
||||||
LocalDate test = LocalDate.of(0, 1, 1);
|
LocalDate test = LocalDate.of(0, 1, 1);
|
||||||
for (long i = date0000x01x01; i < 700000; i++) {
|
for (long i = date0000x01x01; i < date0000x01x01 + 1000; i++) {
|
||||||
assertEquals(LocalDate.ofEpochDay(i), test);
|
assertEquals(LocalDate.ofEpochDay(i), test);
|
||||||
test = next(test);
|
test = next(test);
|
||||||
}
|
}
|
||||||
test = LocalDate.of(0, 1, 1);
|
test = LocalDate.of(0, 1, 1);
|
||||||
for (long i = date0000x01x01; i > -2000000; i--) {
|
for (long i = date0000x01x01; i > date0000x01x01 - 1000; i--) {
|
||||||
assertEquals(LocalDate.ofEpochDay(i), test);
|
assertEquals(LocalDate.ofEpochDay(i), test);
|
||||||
test = previous(test);
|
test = previous(test);
|
||||||
}
|
}
|
||||||
|
@ -1815,12 +1815,12 @@ public class TestLocalDate extends AbstractDateTimeTest {
|
||||||
long date0000x01x01 = -678941 - 40587;
|
long date0000x01x01 = -678941 - 40587;
|
||||||
|
|
||||||
LocalDate test = LocalDate.of(0, 1, 1);
|
LocalDate test = LocalDate.of(0, 1, 1);
|
||||||
for (long i = date0000x01x01; i < 700000; i++) {
|
for (long i = date0000x01x01; i < date0000x01x01 + 1000; i++) {
|
||||||
assertEquals(test.toEpochDay(), i);
|
assertEquals(test.toEpochDay(), i);
|
||||||
test = next(test);
|
test = next(test);
|
||||||
}
|
}
|
||||||
test = LocalDate.of(0, 1, 1);
|
test = LocalDate.of(0, 1, 1);
|
||||||
for (long i = date0000x01x01; i > -2000000; i--) {
|
for (long i = date0000x01x01; i > date0000x01x01 - 1000; i--) {
|
||||||
assertEquals(test.toEpochDay(), i);
|
assertEquals(test.toEpochDay(), i);
|
||||||
test = previous(test);
|
test = previous(test);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1398,7 +1398,7 @@ public class TestLocalDateTime extends AbstractDateTimeTest {
|
||||||
|
|
||||||
@Test(dataProvider = "samplePlusWeeksSymmetry")
|
@Test(dataProvider = "samplePlusWeeksSymmetry")
|
||||||
public void test_plusWeeks_symmetry(LocalDateTime reference) {
|
public void test_plusWeeks_symmetry(LocalDateTime reference) {
|
||||||
for (int weeks = 0; weeks < 365 * 8; weeks++) {
|
for (int weeks = 0; weeks < 52 * 8; weeks++) {
|
||||||
LocalDateTime t = reference.plusWeeks(weeks).plusWeeks(-weeks);
|
LocalDateTime t = reference.plusWeeks(weeks).plusWeeks(-weeks);
|
||||||
assertEquals(t, reference);
|
assertEquals(t, reference);
|
||||||
|
|
||||||
|
@ -2108,7 +2108,7 @@ public class TestLocalDateTime extends AbstractDateTimeTest {
|
||||||
|
|
||||||
@Test(dataProvider = "sampleMinusWeeksSymmetry")
|
@Test(dataProvider = "sampleMinusWeeksSymmetry")
|
||||||
public void test_minusWeeks_symmetry(LocalDateTime reference) {
|
public void test_minusWeeks_symmetry(LocalDateTime reference) {
|
||||||
for (int weeks = 0; weeks < 365 * 8; weeks++) {
|
for (int weeks = 0; weeks < 52 * 8; weeks++) {
|
||||||
LocalDateTime t = reference.minusWeeks(weeks).minusWeeks(-weeks);
|
LocalDateTime t = reference.minusWeeks(weeks).minusWeeks(-weeks);
|
||||||
assertEquals(t, reference);
|
assertEquals(t, reference);
|
||||||
|
|
||||||
|
@ -2728,7 +2728,7 @@ public class TestLocalDateTime extends AbstractDateTimeTest {
|
||||||
public void test_toEpochSecond_afterEpoch() {
|
public void test_toEpochSecond_afterEpoch() {
|
||||||
for (int i = -5; i < 5; i++) {
|
for (int i = -5; i < 5; i++) {
|
||||||
ZoneOffset offset = ZoneOffset.ofHours(i);
|
ZoneOffset offset = ZoneOffset.ofHours(i);
|
||||||
for (int j = 0; j < 100000; j++) {
|
for (int j = 0; j < 1000; j++) {
|
||||||
LocalDateTime a = LocalDateTime.of(1970, 1, 1, 0, 0).plusSeconds(j);
|
LocalDateTime a = LocalDateTime.of(1970, 1, 1, 0, 0).plusSeconds(j);
|
||||||
assertEquals(a.toEpochSecond(offset), j - i * 3600);
|
assertEquals(a.toEpochSecond(offset), j - i * 3600);
|
||||||
}
|
}
|
||||||
|
@ -2737,7 +2737,7 @@ public class TestLocalDateTime extends AbstractDateTimeTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_toEpochSecond_beforeEpoch() {
|
public void test_toEpochSecond_beforeEpoch() {
|
||||||
for (int i = 0; i < 100000; i++) {
|
for (int i = 0; i < 1000; i++) {
|
||||||
LocalDateTime a = LocalDateTime.of(1970, 1, 1, 0, 0).minusSeconds(i);
|
LocalDateTime a = LocalDateTime.of(1970, 1, 1, 0, 0).minusSeconds(i);
|
||||||
assertEquals(a.toEpochSecond(ZoneOffset.UTC), -i);
|
assertEquals(a.toEpochSecond(ZoneOffset.UTC), -i);
|
||||||
}
|
}
|
||||||
|
@ -2808,20 +2808,20 @@ public class TestLocalDateTime extends AbstractDateTimeTest {
|
||||||
for (int j = 0; j < localDateTimes.length; j++) {
|
for (int j = 0; j < localDateTimes.length; j++) {
|
||||||
LocalDateTime b = localDateTimes[j];
|
LocalDateTime b = localDateTimes[j];
|
||||||
if (i < j) {
|
if (i < j) {
|
||||||
assertTrue(a.compareTo(b) < 0, a + " <=> " + b);
|
assertTrue(a.compareTo(b) < 0);
|
||||||
assertEquals(a.isBefore(b), true, a + " <=> " + b);
|
assertTrue(a.isBefore(b));
|
||||||
assertEquals(a.isAfter(b), false, a + " <=> " + b);
|
assertFalse(a.isAfter(b));
|
||||||
assertEquals(a.equals(b), false, a + " <=> " + b);
|
assertFalse(a.equals(b));
|
||||||
} else if (i > j) {
|
} else if (i > j) {
|
||||||
assertTrue(a.compareTo(b) > 0, a + " <=> " + b);
|
assertTrue(a.compareTo(b) > 0);
|
||||||
assertEquals(a.isBefore(b), false, a + " <=> " + b);
|
assertFalse(a.isBefore(b));
|
||||||
assertEquals(a.isAfter(b), true, a + " <=> " + b);
|
assertTrue(a.isAfter(b));
|
||||||
assertEquals(a.equals(b), false, a + " <=> " + b);
|
assertFalse(a.equals(b));
|
||||||
} else {
|
} else {
|
||||||
assertEquals(a.compareTo(b), 0, a + " <=> " + b);
|
assertEquals(a.compareTo(b), 0);
|
||||||
assertEquals(a.isBefore(b), false, a + " <=> " + b);
|
assertFalse(a.isBefore(b));
|
||||||
assertEquals(a.isAfter(b), false, a + " <=> " + b);
|
assertFalse(a.isAfter(b));
|
||||||
assertEquals(a.equals(b), true, a + " <=> " + b);
|
assertTrue(a.equals(b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user