Reimplement StopWatch to use java.time

This commit is contained in:
Gary Gregory 2024-07-18 17:00:28 -04:00
parent 2630268235
commit e32896f89e
2 changed files with 50 additions and 39 deletions

View File

@ -47,6 +47,7 @@ The <action> type attribute can be add,update,fix,remove.
<body> <body>
<release version="3.16.0" date="YYYY-MM-DD" description="This is a feature and maintenance release. Java 8 or later is required."> <release version="3.16.0" date="YYYY-MM-DD" description="This is a feature and maintenance release. Java 8 or later is required.">
<!-- FIX --> <!-- FIX -->
<action type="fix" dev="ggregory" due-to="Gary Gregory">Reimplement StopWatch internals to use java.time.</action>
<!-- ADD --> <!-- ADD -->
<action type="add" dev="ggregory" due-to="Gary Gregory">Add StopWatch.getSplitDuration() and deprecate getSplitTime().</action> <action type="add" dev="ggregory" due-to="Gary Gregory">Add StopWatch.getSplitDuration() and deprecate getSplitTime().</action>
<action type="add" dev="ggregory" due-to="Gary Gregory">Add StopWatch.getStartInstant() and deprecate getStartTime().</action> <action type="add" dev="ggregory" due-to="Gary Gregory">Add StopWatch.getStartInstant() and deprecate getStartTime().</action>

View File

@ -210,27 +210,37 @@ public class StopWatch {
/** /**
* The start time in nanoseconds. * The start time in nanoseconds.
*
* This field can be removed once we move off of Java 8.
*/ */
private long startTimeNanos; private long startTimeNanos;
/** /**
* The start time in milliseconds. * The start Instant.
* <p> * <p>
* nanoTime is only for elapsed time so we need to also store the currentTimeMillis to maintain the old getStartTime API. * nanoTime is only for elapsed time so we need to also store the currentTimeMillis to maintain the old getStartTime API.
* </p> * </p>
* <p>
* On Java 8, Instant has millisecond precision, only later versions use nanoseconds.
* </p>
*/ */
private long startTimeMillis; private Instant startInstant;
/** /**
* The end time in milliseconds. * The end Instant.
* <p> * <p>
* nanoTime is only for elapsed time so we need to also store the currentTimeMillis to maintain the old getStartTime API. * nanoTime is only for elapsed time so we need to also store the currentTimeMillis to maintain the old getStartTime API.
* </p> * </p>
* <p>
* On Java 8, Instant has millisecond precision, only later versions use nanoseconds.
* </p>
*/ */
private long stopTimeMillis; private Instant stopInstant;
/** /**
* The stop time in nanoseconds. * The stop time in nanoseconds.
*
* This field can be removed once we move off of Java 8.
*/ */
private long stopTimeNanos; private long stopTimeNanos;
@ -307,14 +317,14 @@ public class StopWatch {
* @since 3.0 * @since 3.0
*/ */
public long getNanoTime() { public long getNanoTime() {
if (this.runningState == State.STOPPED || this.runningState == State.SUSPENDED) { if (runningState == State.STOPPED || runningState == State.SUSPENDED) {
return this.stopTimeNanos - this.startTimeNanos; return stopTimeNanos - startTimeNanos;
} }
if (this.runningState == State.UNSTARTED) { if (runningState == State.UNSTARTED) {
return 0; return 0;
} }
if (this.runningState == State.RUNNING) { if (runningState == State.RUNNING) {
return System.nanoTime() - this.startTimeNanos; return System.nanoTime() - startTimeNanos;
} }
throw new IllegalStateException("Illegal running state has occurred."); throw new IllegalStateException("Illegal running state has occurred.");
} }
@ -348,10 +358,10 @@ public class StopWatch {
* @since 3.0 * @since 3.0
*/ */
public long getSplitNanoTime() { public long getSplitNanoTime() {
if (this.splitState != SplitState.SPLIT) { if (splitState != SplitState.SPLIT) {
throw new IllegalStateException("Stopwatch must be split to get the split time."); throw new IllegalStateException("Stopwatch must be split to get the split time.");
} }
return this.stopTimeNanos - this.startTimeNanos; return stopTimeNanos - startTimeNanos;
} }
/** /**
@ -393,11 +403,11 @@ public class StopWatch {
*/ */
@Deprecated @Deprecated
public long getStartTime() { public long getStartTime() {
if (this.runningState == State.UNSTARTED) { if (runningState == State.UNSTARTED) {
throw new IllegalStateException("Stopwatch has not been started"); throw new IllegalStateException("Stopwatch has not been started");
} }
// stopTimeNanos stores System.nanoTime() for elapsed time // stopTimeNanos stores System.nanoTime() for elapsed time
return this.startTimeMillis; return startInstant.toEpochMilli();
} }
/** /**
@ -421,11 +431,11 @@ public class StopWatch {
*/ */
@Deprecated @Deprecated
public long getStopTime() { public long getStopTime() {
if (this.runningState == State.UNSTARTED) { if (runningState == State.UNSTARTED) {
throw new IllegalStateException("Stopwatch has not been started"); throw new IllegalStateException("Stopwatch has not been started");
} }
// stopTimeNanos stores System.nanoTime() for elapsed time // stopTimeNanos stores System.nanoTime() for elapsed time
return this.stopTimeMillis; return stopInstant.toEpochMilli();
} }
/** /**
@ -508,8 +518,8 @@ public class StopWatch {
* </p> * </p>
*/ */
public void reset() { public void reset() {
this.runningState = State.UNSTARTED; runningState = State.UNSTARTED;
this.splitState = SplitState.UNSPLIT; splitState = SplitState.UNSPLIT;
} }
/** /**
@ -522,11 +532,11 @@ public class StopWatch {
* @throws IllegalStateException if the StopWatch has not been suspended. * @throws IllegalStateException if the StopWatch has not been suspended.
*/ */
public void resume() { public void resume() {
if (this.runningState != State.SUSPENDED) { if (runningState != State.SUSPENDED) {
throw new IllegalStateException("Stopwatch must be suspended to resume. "); throw new IllegalStateException("Stopwatch must be suspended to resume. ");
} }
this.startTimeNanos += System.nanoTime() - this.stopTimeNanos; startTimeNanos += System.nanoTime() - stopTimeNanos;
this.runningState = State.RUNNING; runningState = State.RUNNING;
} }
/** /**
@ -540,11 +550,11 @@ public class StopWatch {
* @throws IllegalStateException if the StopWatch is not running. * @throws IllegalStateException if the StopWatch is not running.
*/ */
public void split() { public void split() {
if (this.runningState != State.RUNNING) { if (runningState != State.RUNNING) {
throw new IllegalStateException("Stopwatch is not running. "); throw new IllegalStateException("Stopwatch is not running. ");
} }
this.stopTimeNanos = System.nanoTime(); stopTimeNanos = System.nanoTime();
this.splitState = SplitState.SPLIT; splitState = SplitState.SPLIT;
} }
/** /**
@ -557,15 +567,15 @@ public class StopWatch {
* @throws IllegalStateException if the StopWatch is already running. * @throws IllegalStateException if the StopWatch is already running.
*/ */
public void start() { public void start() {
if (this.runningState == State.STOPPED) { if (runningState == State.STOPPED) {
throw new IllegalStateException("Stopwatch must be reset before being restarted. "); throw new IllegalStateException("Stopwatch must be reset before being restarted. ");
} }
if (this.runningState != State.UNSTARTED) { if (runningState != State.UNSTARTED) {
throw new IllegalStateException("Stopwatch already started. "); throw new IllegalStateException("Stopwatch already started. ");
} }
this.startTimeNanos = System.nanoTime(); startTimeNanos = System.nanoTime();
this.startTimeMillis = System.currentTimeMillis(); startInstant = Instant.now();
this.runningState = State.RUNNING; runningState = State.RUNNING;
} }
/** /**
@ -578,14 +588,14 @@ public class StopWatch {
* @throws IllegalStateException if the StopWatch is not running. * @throws IllegalStateException if the StopWatch is not running.
*/ */
public void stop() { public void stop() {
if (this.runningState != State.RUNNING && this.runningState != State.SUSPENDED) { if (runningState != State.RUNNING && runningState != State.SUSPENDED) {
throw new IllegalStateException("Stopwatch is not running. "); throw new IllegalStateException("Stopwatch is not running. ");
} }
if (this.runningState == State.RUNNING) { if (runningState == State.RUNNING) {
this.stopTimeNanos = System.nanoTime(); stopTimeNanos = System.nanoTime();
this.stopTimeMillis = System.currentTimeMillis(); stopInstant = Instant.now();
} }
this.runningState = State.STOPPED; runningState = State.STOPPED;
} }
/** /**
@ -598,12 +608,12 @@ public class StopWatch {
* @throws IllegalStateException if the StopWatch is not currently running. * @throws IllegalStateException if the StopWatch is not currently running.
*/ */
public void suspend() { public void suspend() {
if (this.runningState != State.RUNNING) { if (runningState != State.RUNNING) {
throw new IllegalStateException("Stopwatch must be running to suspend. "); throw new IllegalStateException("Stopwatch must be running to suspend. ");
} }
this.stopTimeNanos = System.nanoTime(); stopTimeNanos = System.nanoTime();
this.stopTimeMillis = System.currentTimeMillis(); stopInstant = Instant.now();
this.runningState = State.SUSPENDED; runningState = State.SUSPENDED;
} }
/** /**
@ -650,10 +660,10 @@ public class StopWatch {
* @throws IllegalStateException if the StopWatch has not been split. * @throws IllegalStateException if the StopWatch has not been split.
*/ */
public void unsplit() { public void unsplit() {
if (this.splitState != SplitState.SPLIT) { if (splitState != SplitState.SPLIT) {
throw new IllegalStateException("Stopwatch has not been split. "); throw new IllegalStateException("Stopwatch has not been split. ");
} }
this.splitState = SplitState.UNSPLIT; splitState = SplitState.UNSPLIT;
} }
} }