package xapi.jre.time; import xapi.annotation.inject.SingletonOverride; import xapi.platform.AndroidPlatform; import xapi.platform.JrePlatform; import xapi.time.impl.TimeServiceDefault; import xapi.time.service.TimeService; import xapi.util.X_String; import java.util.Calendar; import java.util.concurrent.locks.LockSupport; @JrePlatform @AndroidPlatform @SingletonOverride(implFor=TimeService.class,priority=Integer.MIN_VALUE+2) public class JreTimeServiceHighPrecision extends TimeServiceDefault{ private static final long serialVersionUID = 7851025085789327954L; private final double nanoBirth; public JreTimeServiceHighPrecision() { nanoBirth = System.nanoTime(); } @Override public double millis() { return (birth()+ (System.nanoTime() - nanoBirth) * nano_to_milli); } @Override public double tick() { final double start = millis(); return delta.updateAndGet(i -> { // Unless tick is called very, very rapidly, // the next nanotime will be greater than our current time. if (start > i) { return start; } // When called quickly, we want to return the smallest possible // floating point that is greater than the previous time, // as well as the current returnable time... i = i + TIME_ULP; // However, we don't want to get more than a millisecond out of sync... // So, we will wait until our nowPlusOne is within 1 milli of now() while (i > millis() + getMarginOfError()) { // Release our thread so that instead of busy-waiting, // we will let other threads have a chance to do some work. LockSupport.parkNanos(1); } return i; }); } @Override public String timestamp() { Calendar c = Calendar.getInstance(); return X_String.toTimestamp( c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DATE), c.get(Calendar.HOUR), c.get(Calendar.MINUTE), c.get(Calendar.MILLISECOND), c.getTimeZone().getOffset(c.getTimeInMillis()) / 60000); } }