New API:  Allow creating timestamp with custom time.
MODIFY
dd-trace/src/main/java/datadog/trace/tracer/Clock.java
dd-trace/src/main/java/datadog/trace/tracer/Clock.java
@@ -47,6 +47,15 @@ class Clock {
return new Timestamp(this);
}
+ /**
+ * Create new timestamp instance for current time.
+ *
+ * @return new timestamp capturing current time.
+ */
+ public Timestamp createTimestampForTime(final long time, final TimeUnit unit) {
+ return new Timestamp(this, time, unit);
+ }
+
/**
* Get the current nanos ticks (i.e. System.nanoTime()), this method can't be use for date
* accuracy (only duration calculations).

MODIFY
dd-trace/src/main/java/datadog/trace/tracer/Timestamp.java
dd-trace/src/main/java/datadog/trace/tracer/Timestamp.java
@@ -3,6 +3,7 @@ package datadog.trace.tracer;
import static java.lang.Math.max;
import com.fasterxml.jackson.annotation.JsonValue;
+import java.util.concurrent.TimeUnit;
import lombok.EqualsAndHashCode;
/**
@@ -26,6 +27,20 @@ public class Timestamp {
nanoTicks = clock.nanoTicks();
}
+ /**
+ * Create timestamp for a given clock and given start time and precision
+ *
+ * @param clock clock instance
+ */
+ Timestamp(final Clock clock, final long time, final TimeUnit unit) {
+ this.clock = clock;
+ final long currentTime = clock.epochTimeNano();
+ final long currentTick = clock.nanoTicks();
+ final long desiredTime = unit.toNanos(time);
+ final long offset = currentTime - desiredTime;
+ nanoTicks = currentTick - offset;
+ }
+
/** @return clock instance used by this timestamp */
Clock getClock() {
return clock;

MODIFY
dd-trace/src/main/java/datadog/trace/tracer/Tracer.java
dd-trace/src/main/java/datadog/trace/tracer/Tracer.java
@@ -9,6 +9,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
@@ -74,6 +75,14 @@ public class Tracer implements Closeable {
return new Clock(this).createCurrentTimestamp();
}
+ /**
+ * @return timestamp for given time. Note: this is mainly useful when there is no 'current' trace.
+ * If there is 'current' trace already then one should use it to get timestamps.
+ */
+ public Timestamp createTimestampForTime(final long time, final TimeUnit unit) {
+ return new Clock(this).createTimestampForTime(time, unit);
+ }
+
/**
* Construct a new trace using this tracer's settings and return the root span.
*

MODIFY
dd-trace/src/test/groovy/datadog/trace/tracer/ClockTest.groovy
dd-trace/src/test/groovy/datadog/trace/tracer/ClockTest.groovy
@@ -43,6 +43,17 @@ class ClockTest extends Specification {
timestamp.getClock() == clock
}
+ def "test timestamp creation with custom time"() {
+ setup:
+ def clock = new Clock(tracer)
+
+ when:
+ def timestamp = clock.createTimestampForTime(1, TimeUnit.SECONDS)
+
+ then:
+ timestamp.getClock() == clock
+ }
+
def "test equals"() {
when:
EqualsVerifier.forClass(Clock).suppress(Warning.STRICT_INHERITANCE).verify()

MODIFY
dd-trace/src/test/groovy/datadog/trace/tracer/TimestampTest.groovy
dd-trace/src/test/groovy/datadog/trace/tracer/TimestampTest.groovy
@@ -5,6 +5,9 @@ import nl.jqno.equalsverifier.EqualsVerifier
import nl.jqno.equalsverifier.Warning
import spock.lang.Specification
+import static java.util.concurrent.TimeUnit.MICROSECONDS
+import static java.util.concurrent.TimeUnit.NANOSECONDS
+
class TimestampTest extends Specification {
private static final long CLOCK_START_TIME = 100
@@ -36,11 +39,33 @@ class TimestampTest extends Specification {
clock.getStartNanoTicks() >> CLOCK_START_NANO_TICKS
def timestamp = new Timestamp(clock)
+ when:
+ def duration = timestamp.getDuration(FINISH_TIME)
+
+ then:
+ duration == 400
+ 0 * tracer._
+ }
+
+ def "test timestamp with custom time"() {
+ setup:
+ clock.nanoTicks() >> CLOCK_NANO_TICKS
+ clock.getStartTimeNano() >> CLOCK_START_TIME
+ clock.getStartNanoTicks() >> CLOCK_START_NANO_TICKS
+ def timestamp = new Timestamp(clock, CLOCK_START_TIME + offset, unit)
+
when:
def time = timestamp.getTime()
then:
- time == 300
+ time == expected
+
+ where:
+ offset | unit | expected
+ 10 | NANOSECONDS | 410
+ -20 | NANOSECONDS | 380
+ 3 | MICROSECONDS | 103300
+ -4 | MICROSECONDS | 96300
}
def "test getDuration with literal finish time"() {

New API:  Allow creating timestamp with custom time.