/**
*
* Funf: Open Sensing Framework
* Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland.
* Acknowledgments: Alan Gardner
* Contact: nadav@media.mit.edu
*
* This file is part of Funf.
*
* Funf is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Funf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Funf. If not, see <http://www.gnu.org/licenses/>.
*
*/
package edu.mit.media.funf.time;
import java.math.BigDecimal;
import java.math.RoundingMode;
import android.util.Log;
public class TimeUtil {
private static final BigDecimal TWO = new BigDecimal(2);
public static final int
NANO = 9,
MICRO = 6,
MILLI = 3;
/**
* Returns a BigDecimal timestamp in seconds with millisecond precision, using System.currentTimeMillis()
* @return
*/
public static BigDecimal getTimestamp() {
return DecimalTimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
}
/**
* Returns a BigDecimal timestamp in seconds with microsecond precision,
* using System.nanoTime() and uptimeNanosToTimestamp()
* @return
*/
public static BigDecimal getTimestampWithMicroPrecision() {
return TimeUtil.uptimeNanosToTimestamp(System.nanoTime());
}
public static long secondsToMillis(Number seconds) {
return DecimalTimeUnit.SECONDS.toMillis(seconds).longValue();
}
/**
* Aligns the nano seconds to the start of a new millisecond.
* This should be called whenever device wakes up from sleep.
*/
public static void calibrateNanosConversion() {
long originalMillis = System.currentTimeMillis();
long updatedMillis = originalMillis;
while(originalMillis == updatedMillis) {
updatedMillis = System.currentTimeMillis();
}
TimeUtil.referenceNanos = System.nanoTime();
TimeUtil.referenceMillis = updatedMillis;
TimeUtil.secondsOffset = BigDecimal.valueOf(TimeUtil.referenceMillis, MILLI).subtract(BigDecimal.valueOf(TimeUtil.referenceNanos, NANO));
}
public static BigDecimal roundToMilliPrecision(BigDecimal timestamp) {
return timestamp.setScale(MILLI, RoundingMode.HALF_EVEN);
}
public static BigDecimal roundToMicroPrecision(BigDecimal timestamp) {
return timestamp.setScale(MICRO, RoundingMode.HALF_EVEN);
}
/**
* Converts uptime nanos to a real UTC timestamp in seconds.
* @param nanos
* @return
*/
public static BigDecimal uptimeNanosToTimestamp(long nanos) {
if (TimeUtil.secondsOffset == null) {
calibrateNanosConversion();
} else {
long currentMillis1 = System.currentTimeMillis();
long currentNanos = System.nanoTime();
long currentMillis2 = System.currentTimeMillis();
BigDecimal currentTimeStamp = DecimalTimeUnit.MILLISECONDS.toSeconds(((double)(currentMillis1 + currentMillis2))/2.0);
if (TimeUtil._uptimeNanosToTimestamp(currentNanos).subtract(currentTimeStamp).abs().doubleValue() > TimeUtil.CLOCK_OFFSET_TOLERANCE) {
calibrateNanosConversion();
}
}
return TimeUtil._uptimeNanosToTimestamp(nanos);
}
// Round to microseconds, because of the inaccuracy associated with our method of syncing the clocks
public static BigDecimal _uptimeNanosToTimestamp(long nanos) {
return roundToMicroPrecision(BigDecimal.valueOf(nanos, NANO).add(TimeUtil.secondsOffset));
}
public static final double CLOCK_OFFSET_TOLERANCE = 0.002;
public static BigDecimal secondsOffset;
public static long referenceMillis;
public static long referenceNanos;
}