From 2924af963d26985bf68e0891d26225b4198b9f06 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 5 May 2020 18:15:44 +0300 Subject: [PATCH] java.time: add support for time zones --- .../classlib/impl/tz/AliasDateTimeZone.java | 6 + .../classlib/impl/tz/CachedDateTimeZone.java | 7 + .../teavm/classlib/impl/tz/DateTimeZone.java | 4 + .../classlib/impl/tz/DateTimeZoneBuilder.java | 134 ++++++++++++++++- .../classlib/impl/tz/FixedDateTimeZone.java | 18 +++ .../threeten/bp/zone/JodaRulesProvider.java | 62 ++++++++ .../threeten/bp/zone/StandardZoneRules.java | 3 +- .../bp/zone/ZoneRulesInitializer.java | 137 ------------------ .../threeten/bp/zone/ZoneRulesProvider.java | 3 +- .../classlib/java/time/TestLocalDate.java | 8 +- .../classlib/java/time/TestLocalDateTime.java | 32 ++-- 11 files changed, 252 insertions(+), 162 deletions(-) create mode 100644 classlib/src/main/java/org/threeten/bp/zone/JodaRulesProvider.java delete mode 100644 classlib/src/main/java/org/threeten/bp/zone/ZoneRulesInitializer.java diff --git a/classlib/src/main/java/org/teavm/classlib/impl/tz/AliasDateTimeZone.java b/classlib/src/main/java/org/teavm/classlib/impl/tz/AliasDateTimeZone.java index 60e46774b..ce9a64082 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/tz/AliasDateTimeZone.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/tz/AliasDateTimeZone.java @@ -15,6 +15,7 @@ */ package org.teavm.classlib.impl.tz; +import java.time.zone.ZoneRules; import org.teavm.classlib.impl.Base46; public class AliasDateTimeZone extends StorableDateTimeZone { @@ -55,4 +56,9 @@ public class AliasDateTimeZone extends StorableDateTimeZone { Base46.encodeUnsigned(sb, ALIAS); sb.append(innerZone.getID()); } + + @Override + public ZoneRules asZoneRules() { + return innerZone.asZoneRules(); + } } diff --git a/classlib/src/main/java/org/teavm/classlib/impl/tz/CachedDateTimeZone.java b/classlib/src/main/java/org/teavm/classlib/impl/tz/CachedDateTimeZone.java index c7af08d1f..c40786957 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/tz/CachedDateTimeZone.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/tz/CachedDateTimeZone.java @@ -15,6 +15,8 @@ */ package org.teavm.classlib.impl.tz; +import java.time.zone.ZoneRules; + /** * 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 @@ -97,6 +99,11 @@ public final class CachedDateTimeZone extends StorableDateTimeZone { return iZone.previousTransition(instant); } + @Override + public ZoneRules asZoneRules() { + return iZone.asZoneRules(); + } + // Although accessed by multiple threads, this method doesn't need to be // synchronized. diff --git a/classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZone.java b/classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZone.java index aa4abeedc..4ab679e9f 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZone.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZone.java @@ -15,6 +15,8 @@ */ package org.teavm.classlib.impl.tz; +import java.time.zone.ZoneRules; + /** * DateTimeZone represents a time zone. *

@@ -485,4 +487,6 @@ public abstract class DateTimeZone { * @return milliseconds from 1970-01-01T00:00:00Z */ public abstract long previousTransition(long instant); + + public abstract ZoneRules asZoneRules(); } diff --git a/classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZoneBuilder.java b/classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZoneBuilder.java index 773cebff6..02c387968 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZoneBuilder.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZoneBuilder.java @@ -15,6 +15,14 @@ */ 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 org.teavm.classlib.impl.Base46; import org.teavm.classlib.impl.CharFlow; @@ -323,7 +331,7 @@ public class DateTimeZoneBuilder { } Base46.encodeUnsigned(sb, flags); Base46.encodeUnsigned(sb, iMonthOfYear); - Base46.encodeUnsigned(sb, iDayOfMonth); + Base46.encode(sb, iDayOfMonth); if (iDayOfWeek != 0) { Base46.encode(sb, iDayOfWeek); } @@ -350,7 +358,7 @@ public class DateTimeZoneBuilder { } int monthOfYear = Base46.decodeUnsigned(flow); - int dayOfMonth = Base46.decodeUnsigned(flow); + int dayOfMonth = Base46.decode(flow); int dayOfWeek = hasDayOfWeek ? Base46.decode(flow) : 0; int millisOfDay = (int) StorableDateTimeZone.readUnsignedTime(flow); return new OfYear(mode, monthOfYear, dayOfMonth, dayOfWeek, advance, millisOfDay); @@ -1065,6 +1073,11 @@ public class DateTimeZoneBuilder { Recurrence endRecurrence = Recurrence.read(flow); return new DSTZone(id, standardOffset, startRecurrence, endRecurrence); } + + @Override + public ZoneRules asZoneRules() { + return null; + } } static final class PrecalculatedZone extends StorableDateTimeZone { @@ -1350,6 +1363,117 @@ public class DateTimeZoneBuilder { return false; } + + @Override + public ZoneRules asZoneRules() { + List standardTransitions = new ArrayList<>(); + List 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 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 { @@ -1521,5 +1645,11 @@ public class DateTimeZoneBuilder { } return filtered; } + + @Override + public ZoneRules asZoneRules() { + initZone(); + return zone.asZoneRules(); + } } } diff --git a/classlib/src/main/java/org/teavm/classlib/impl/tz/FixedDateTimeZone.java b/classlib/src/main/java/org/teavm/classlib/impl/tz/FixedDateTimeZone.java index 72025bc83..26a7d7304 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/tz/FixedDateTimeZone.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/tz/FixedDateTimeZone.java @@ -15,6 +15,9 @@ */ 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.CharFlow; @@ -78,4 +81,19 @@ public final class FixedDateTimeZone extends StorableDateTimeZone { int standardOffset = (int) readTime(flow); 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() + ); + } + } } diff --git a/classlib/src/main/java/org/threeten/bp/zone/JodaRulesProvider.java b/classlib/src/main/java/org/threeten/bp/zone/JodaRulesProvider.java new file mode 100644 index 000000000..e60599301 --- /dev/null +++ b/classlib/src/main/java/org/threeten/bp/zone/JodaRulesProvider.java @@ -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 zoneIds; + private Map cache = new HashMap<>(); + + @Override + protected Set 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 provideVersions(String zoneId) { + ZoneRules result = provideRules(zoneId, false); + TreeMap map = new TreeMap<>(); + map.put("", result); + return map; + } +} diff --git a/classlib/src/main/java/org/threeten/bp/zone/StandardZoneRules.java b/classlib/src/main/java/org/threeten/bp/zone/StandardZoneRules.java index 58a20a654..ee4be1914 100644 --- a/classlib/src/main/java/org/threeten/bp/zone/StandardZoneRules.java +++ b/classlib/src/main/java/org/threeten/bp/zone/StandardZoneRules.java @@ -38,7 +38,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; - import org.threeten.bp.Duration; import org.threeten.bp.Instant; import org.threeten.bp.LocalDate; @@ -90,7 +89,7 @@ final class StandardZoneRules extends ZoneRules implements Serializable { /** * The map of recent transitions. */ - private final Map lastRulesCache = new HashMap<>(); + private final Map lastRulesCache = new HashMap<>(); /** * Creates an instance. diff --git a/classlib/src/main/java/org/threeten/bp/zone/ZoneRulesInitializer.java b/classlib/src/main/java/org/threeten/bp/zone/ZoneRulesInitializer.java deleted file mode 100644 index bc01aa072..000000000 --- a/classlib/src/main/java/org/threeten/bp/zone/ZoneRulesInitializer.java +++ /dev/null @@ -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. - *

- * 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. - *

- * The initializer must be set before class loading of any other ThreeTen-Backport class to have any effect! - *

- * 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. - *

- * 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. - *

- * 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)}. - *

- * It is vital that the instance of {@link ZoneRulesProvider} is not created until this method is invoked. - *

- * 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 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; - } - } - } - } - } - -} diff --git a/classlib/src/main/java/org/threeten/bp/zone/ZoneRulesProvider.java b/classlib/src/main/java/org/threeten/bp/zone/ZoneRulesProvider.java index b4d78ec43..7fbd7aad6 100644 --- a/classlib/src/main/java/org/threeten/bp/zone/ZoneRulesProvider.java +++ b/classlib/src/main/java/org/threeten/bp/zone/ZoneRulesProvider.java @@ -79,8 +79,9 @@ public abstract class ZoneRulesProvider { * The lookup from zone region ID to provider. */ private static final Map ZONES = new HashMap<>(); + static { - ZoneRulesInitializer.initialize(); + registerProvider0(new JodaRulesProvider()); } //------------------------------------------------------------------------- diff --git a/tests/src/test/java/org/teavm/classlib/java/time/TestLocalDate.java b/tests/src/test/java/org/teavm/classlib/java/time/TestLocalDate.java index 6c3800047..670fae434 100644 --- a/tests/src/test/java/org/teavm/classlib/java/time/TestLocalDate.java +++ b/tests/src/test/java/org/teavm/classlib/java/time/TestLocalDate.java @@ -452,12 +452,12 @@ public class TestLocalDate extends AbstractDateTimeTest { assertEquals(LocalDate.ofEpochDay(minValidEpochdays), LocalDate.of(Year.MIN_VALUE, 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); test = next(test); } 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); test = previous(test); } @@ -1815,12 +1815,12 @@ public class TestLocalDate extends AbstractDateTimeTest { long date0000x01x01 = -678941 - 40587; 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); test = next(test); } 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); test = previous(test); } diff --git a/tests/src/test/java/org/teavm/classlib/java/time/TestLocalDateTime.java b/tests/src/test/java/org/teavm/classlib/java/time/TestLocalDateTime.java index a39677c09..dc7830679 100644 --- a/tests/src/test/java/org/teavm/classlib/java/time/TestLocalDateTime.java +++ b/tests/src/test/java/org/teavm/classlib/java/time/TestLocalDateTime.java @@ -1398,7 +1398,7 @@ public class TestLocalDateTime extends AbstractDateTimeTest { @Test(dataProvider = "samplePlusWeeksSymmetry") 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); assertEquals(t, reference); @@ -2108,7 +2108,7 @@ public class TestLocalDateTime extends AbstractDateTimeTest { @Test(dataProvider = "sampleMinusWeeksSymmetry") 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); assertEquals(t, reference); @@ -2728,7 +2728,7 @@ public class TestLocalDateTime extends AbstractDateTimeTest { public void test_toEpochSecond_afterEpoch() { for (int i = -5; i < 5; 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); assertEquals(a.toEpochSecond(offset), j - i * 3600); } @@ -2737,7 +2737,7 @@ public class TestLocalDateTime extends AbstractDateTimeTest { @Test 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); assertEquals(a.toEpochSecond(ZoneOffset.UTC), -i); } @@ -2808,20 +2808,20 @@ public class TestLocalDateTime extends AbstractDateTimeTest { for (int j = 0; j < localDateTimes.length; j++) { LocalDateTime b = localDateTimes[j]; if (i < j) { - assertTrue(a.compareTo(b) < 0, a + " <=> " + b); - assertEquals(a.isBefore(b), true, a + " <=> " + b); - assertEquals(a.isAfter(b), false, a + " <=> " + b); - assertEquals(a.equals(b), false, a + " <=> " + b); + assertTrue(a.compareTo(b) < 0); + assertTrue(a.isBefore(b)); + assertFalse(a.isAfter(b)); + assertFalse(a.equals(b)); } else if (i > j) { - assertTrue(a.compareTo(b) > 0, a + " <=> " + b); - assertEquals(a.isBefore(b), false, a + " <=> " + b); - assertEquals(a.isAfter(b), true, a + " <=> " + b); - assertEquals(a.equals(b), false, a + " <=> " + b); + assertTrue(a.compareTo(b) > 0); + assertFalse(a.isBefore(b)); + assertTrue(a.isAfter(b)); + assertFalse(a.equals(b)); } else { - assertEquals(a.compareTo(b), 0, a + " <=> " + b); - assertEquals(a.isBefore(b), false, a + " <=> " + b); - assertEquals(a.isAfter(b), false, a + " <=> " + b); - assertEquals(a.equals(b), true, a + " <=> " + b); + assertEquals(a.compareTo(b), 0); + assertFalse(a.isBefore(b)); + assertFalse(a.isAfter(b)); + assertTrue(a.equals(b)); } } }