< prev index next >
jdk/test/java/time/test/java/time/TestClock_System.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
--- 1,7 ----
/*
! * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*** 60,70 ****
--- 60,72 ----
package test.java.time;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertSame;
+ import java.lang.reflect.Field;
import java.time.Clock;
+ import java.time.Instant;
import java.time.ZoneId;
import org.testng.annotations.Test;
/**
*** 85,90 ****
--- 87,386 ----
public void test_toString() {
Clock test = Clock.system(PARIS);
assertEquals(test.toString(), "SystemClock[Europe/Paris]");
}
+ //-----------------------------------------------------------------------
+
+ private static String formatTime(String prefix, Instant time) {
+ return prefix + ": " + time + " - seconds: "
+ + time.getEpochSecond() + ", nanos: "
+ + time.getNano();
+ }
+
+ public void test_ClockResolution() {
+ Clock highestUTC = Clock.systemUTC();
+
+ Instant start = Instant.ofEpochMilli(System.currentTimeMillis());
+
+ try {
+ // smoke test
+ Instant system1 = Instant.ofEpochMilli(System.currentTimeMillis());
+ Instant system2 = Instant.ofEpochMilli(System.currentTimeMillis());
+ Instant highest1 = highestUTC.instant();
+ Instant highest2 = highestUTC.instant();
+ System.out.println(formatTime("\nsystemUTC #1 ", system1));
+ System.out.println(formatTime("systemUTC #2 ", system2));
+ System.out.println(formatTime("highestResolutionUTC #1 ", highest1));
+ System.out.println(formatTime("highestResolutionUTC #2 ", highest2));
+
+ if (system2.isBefore(system1)) {
+ System.err.println("system2 is before system1!");
+ System.err.println(formatTime("\n\tsystem1", system1));
+ System.err.println(formatTime("\n\tsystem2", system2));
+ throw new RuntimeException("system2 is before system1!"
+ + formatTime("\n\tsystem1", system1)
+ + formatTime("\n\tsystem2", system2));
+ }
+ if (highest2.isBefore(highest1)) {
+ System.err.println("highest2 is before highest1!");
+ System.err.println(formatTime("\n\thighest1", system1));
+ System.err.println(formatTime("\n\tsystem2", highest2));
+ throw new RuntimeException("highest2 is before system1!"
+ + formatTime("\n\thighest1", system1)
+ + formatTime("\n\tsystem2", highest2));
+ }
+
+ // better test - but depends on implementation details.
+ // we're not rounding - so highest1 should be greater or equal to
+ // system1
+ system1 = Instant.ofEpochMilli(System.currentTimeMillis());
+ highest1 = highestUTC.instant();
+
+ System.out.println(formatTime("\nsystemUTC ", system1));
+ System.out.println(formatTime("highestResolutionUTC ", highest1));
+
+ if (highest1.isBefore(system1)) {
+ System.err.println("highest1 is before system1!");
+ System.err.println(formatTime("\n\tsystem1", system1));
+ System.err.println(formatTime("\n\thighest1", highest1));
+ throw new RuntimeException("highest1 is before system1!"
+ + formatTime("\n\tsystem1", system1)
+ + formatTime("\n\thighest1", highest1));
+ }
+
+ int count=0;
+ // let's preheat the system a bit:
+ for (int i = 0; i < 1000 ; i++) {
+ system1 = Instant.ofEpochMilli(System.currentTimeMillis());
+ highest1 = highestUTC.instant();
+ final int sysnan = system1.getNano();
+ final int nanos = highest1.getNano();
+ if ((nanos % 1000000) > 0) {
+ count++; // we have micro seconds
+ }
+ if ((sysnan % 1000000) > 0) {
+ throw new RuntimeException("Expected only millisecconds "
+ + "precision for systemUTC, found "
+ + (sysnan % 1000000) + " remainder.");
+ }
+ }
+ System.out.println("\nNumber of time stamps which had better than"
+ + " millisecond precision: "+count+"/"+1000);
+ System.out.println(formatTime("\nsystemUTC ", system1));
+ System.out.println(formatTime("highestResolutionUTC ", highest1));
+ if (count == 0) {
+ System.err.println("Something is strange: no microsecond "
+ + "precision with highestResolutionUTC?");
+ throw new RuntimeException("Micro second preccision not reached");
+ }
+
+ // check again
+ if (highest1.isBefore(system1)) {
+ System.err.println("highest1 is before system1!");
+ System.err.println(formatTime("\n\tsystem1", system1));
+ System.err.println(formatTime("\n\thighest1", highest1));
+ throw new RuntimeException("highest1 is before system1!"
+ + formatTime("\n\tsystem1", system1)
+ + formatTime("\n\thighest1", highest1));
+ }
+
+ // leap of faith: ensure that highest1 is from within 10 secs of
+ // system1
+ if (highest1.toEpochMilli() != system1.toEpochMilli()) {
+ long delta = highest1.getEpochSecond() - system1.getEpochSecond();
+ if (delta > 10) {
+ throw new RuntimeException("Unexpected long delay between two clocks ("
+ + delta + " seconds)"
+ + formatTime("\n\t system1", system1)
+ + formatTime("\n\t highest1", highest1));
+
+ }
+ } else {
+ System.out.println("You won the lottery: the two dates are within 1 millisecond!\n");
+ }
+
+ } finally {
+ Instant stop = Instant.ofEpochMilli(System.currentTimeMillis());
+ if (start.isAfter(stop)) {
+ // This should not happen - but can (un)probably be observed
+ // when switching to summer time, or if another application
+ // is switching the system date...
+ System.err.println("Cannot test - date was setback: "
+ + formatTime("\n\tstarted at", start)
+ + formatTime("\n\tstopped at", stop) + "\n");
+ return; // will prevent exceptions from being propagated.
+ }
+ }
+ }
+
+ static final long MAX_OFFSET = 0x0100000000L;
+ static final long MIN_OFFSET = -MAX_OFFSET;
+
+ // A helper class to test that SystemClock correctly recomputes
+ // its offset.
+ static class SystemClockOffset {
+
+ static final int MILLIS_IN_SECOND = 1000;
+ static final int NANOS_IN_MILLI = 1000_000;
+ static final int NANOS_IN_MICRO = 1000;
+ static final int NANOS_IN_SECOND = 1000_000_000;
+
+ static final boolean verbose = true;
+ static final Clock systemUTC = Clock.systemUTC();
+ static final Field offsetField;
+
+ static {
+ try {
+ offsetField = Class.forName("java.time.Clock$SystemClock").getDeclaredField("offset");
+ offsetField.setAccessible(true);
+ } catch (ClassNotFoundException | NoSuchFieldException ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ static enum Answer {
+
+ YES, // isOffLimit = YES: we must get -1
+ NO, // isOffLimit = NO: we must not not get -1
+ MAYBE // isOffLimit = MAYBE: we might get -1 or a valid adjustment.
+ };
+
+ static long distance(long one, long two) {
+ return one > two ? Math.subtractExact(one, two)
+ : Math.subtractExact(two, one);
+ }
+
+ static Answer isOffLimits(long before, long after, long offset) {
+ long relativeDistanceBefore = distance(before, offset);
+ long relativeDistanceAfter = distance(after, offset);
+ if (relativeDistanceBefore >= MAX_OFFSET && relativeDistanceAfter >= MAX_OFFSET) {
+ return Answer.YES;
+ }
+ if (relativeDistanceBefore < MAX_OFFSET && relativeDistanceAfter < MAX_OFFSET) {
+ if (relativeDistanceBefore == 0 || relativeDistanceAfter == 0) {
+ return Answer.MAYBE; // unlucky case where
+ }
+ return Answer.NO;
+ }
+ return Answer.MAYBE;
+ }
+
+ static void testWithOffset(String name, long offset)
+ throws IllegalAccessException {
+ testWithOffset(name, offset, systemUTC);
+ }
+
+ static void testWithOffset(String name, long offset, Clock clock)
+ throws IllegalAccessException {
+ offsetField.set(clock, offset);
+ long beforeMillis = System.currentTimeMillis();
+ final Instant instant = clock.instant();
+ long afterMillis = System.currentTimeMillis();
+ long actualOffset = offsetField.getLong(clock);
+ long instantMillis = instant.getEpochSecond() * MILLIS_IN_SECOND
+ + instant.getNano() / NANOS_IN_MILLI;
+ if (instantMillis < beforeMillis || instantMillis > afterMillis) {
+ throw new RuntimeException(name
+ + ": Invalid instant: " + instant
+ + " (~" + instantMillis + "ms)"
+ + " when time in millis is in ["
+ + beforeMillis + ", " + afterMillis
+ + "] and offset in seconds is " + offset);
+ }
+ Answer isOffLimits = isOffLimits(beforeMillis / MILLIS_IN_SECOND,
+ afterMillis / MILLIS_IN_SECOND, offset);
+ switch (isOffLimits) {
+ case YES:
+ if (actualOffset == offset) {
+ throw new RuntimeException(name
+ + ": offset was offlimit but was not recomputed "
+ + " when time in millis is in ["
+ + beforeMillis + ", " + afterMillis
+ + "] and offset in seconds was " + offset);
+ }
+ break;
+ case NO:
+ if (actualOffset != offset) {
+ throw new RuntimeException(name
+ + ": offset was not offlimit but was recomputed.");
+ }
+ break;
+ default:
+ break;
+ }
+ if (distance(actualOffset, instant.getEpochSecond()) >= MAX_OFFSET) {
+ throw new RuntimeException(name + ": Actual offset is too far off:"
+ + " offset=" + actualOffset
+ + "instant.seconds=" + instant.getEpochSecond());
+ }
+ long adjustment = (instant.getEpochSecond() - actualOffset) * NANOS_IN_SECOND
+ + instant.getNano();
+ validateAdjustment(name, actualOffset, beforeMillis, afterMillis, adjustment);
+ }
+
+ static void validateAdjustment(String name, long offset, long beforeMillis,
+ long afterMillis, long adjustment) {
+ System.out.println("Validating adjustment: " + adjustment);
+ long expectedMax = distance(offset, beforeMillis / MILLIS_IN_SECOND)
+ * NANOS_IN_SECOND
+ + (beforeMillis % MILLIS_IN_SECOND) * NANOS_IN_MILLI
+ + (afterMillis - beforeMillis + 1) * NANOS_IN_MILLI;
+ long absoluteAdjustment = distance(0, adjustment);
+ if (absoluteAdjustment > expectedMax) {
+ long adjSec = absoluteAdjustment / NANOS_IN_SECOND;
+ long adjMil = (absoluteAdjustment % NANOS_IN_SECOND) / NANOS_IN_MILLI;
+ long adjMic = (absoluteAdjustment % NANOS_IN_MILLI) / NANOS_IN_MICRO;
+ long adjNan = (absoluteAdjustment % NANOS_IN_MICRO);
+ long expSec = expectedMax / NANOS_IN_SECOND;
+ long expMil = (expectedMax % NANOS_IN_SECOND) / NANOS_IN_MILLI;
+ long expMic = (expectedMax % NANOS_IN_MILLI) / NANOS_IN_MICRO;
+ long expNan = (expectedMax % NANOS_IN_MICRO);
+ System.err.println("Excessive adjustment: " + adjSec + "s, "
+ + adjMil + "ms, " + adjMic + "mics, " + adjNan + "ns");
+ System.err.println("Epected max: " + expSec + "s, "
+ + expMil + "ms, " + expMic + "mics, " + expNan + "ns");
+
+ throw new RuntimeException(name
+ + ": Excessive adjustment: " + adjustment
+ + " when time in millis is in ["
+ + beforeMillis + ", " + afterMillis
+ + "] and offset in seconds is " + offset);
+ }
+ }
+ }
+
+ public void test_OffsetRegular() throws IllegalAccessException {
+ System.out.println("*** Testing regular cases ***");
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000",
+ System.currentTimeMillis()/1000);
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - 1024",
+ System.currentTimeMillis()/1000 - 1024);
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + 1024",
+ System.currentTimeMillis()/1000 + 1024);
+ }
+
+ public void test_OffsetLimits() throws IllegalAccessException {
+ System.out.println("*** Testing limits ***");
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET + 1",
+ System.currentTimeMillis()/1000 - MAX_OFFSET + 1);
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET - 1",
+ System.currentTimeMillis()/1000 + MAX_OFFSET - 1);
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET",
+ System.currentTimeMillis()/1000 - MAX_OFFSET);
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET",
+ System.currentTimeMillis()/1000 + MAX_OFFSET);
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - MAX_OFFSET - 1024",
+ System.currentTimeMillis()/1000 - MAX_OFFSET - 1024);
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 + MAX_OFFSET + 1024",
+ System.currentTimeMillis()/1000 + MAX_OFFSET + 1024);
+ SystemClockOffset.testWithOffset("0", 0);
+ SystemClockOffset.testWithOffset("-1", -1);
+ SystemClockOffset.testWithOffset("Integer.MAX_VALUE + System.currentTimeMillis()/1000",
+ ((long)Integer.MAX_VALUE) + System.currentTimeMillis()/1000);
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - Integer.MIN_VALUE",
+ System.currentTimeMillis()/1000 - Integer.MIN_VALUE);
+ SystemClockOffset.testWithOffset("Long.MAX_VALUE", Long.MAX_VALUE);
+ SystemClockOffset.testWithOffset("System.currentTimeMillis()/1000 - Long.MIN_VALUE",
+ (Long.MIN_VALUE + System.currentTimeMillis()/1000)*-1);
+ }
}
< prev index next >