Accelerometer SensorEvent timestamp
Im currently working on a android application.. I have to log the accelerometer sensor event coordinate with event time. I got the sensor event timestamp like "3497855005850" but i am not able to convert event timestamp into user reada开发者_StackOverflow中文版ble date time format.Thanks in advance
How can i convert SensorEvent timestamp to unix timestamp?
The sensor timestamp is actually nanoseconds of uptime, not system time in nanoseconds. See SensorEvent.timestamp to absolute (utc) timestamp?.
In theory, you can convert sensor timestamp to time in milliseconds using:
long timeInMillis = (new Date()).getTime()
+ (sensorEvent.timestamp - System.nanoTime()) / 1000000L;
You could even bracket the (new Date()).getTime()
call with two System.nanoTime()
calls and average them to get closer to the actual offset.
Then you can format the sensor time as date and time.
You can set referent time variables in your onSensorChanged(SensorEvent)
function.
Reference for current time and event time. When event arrives subtract sensor referent time from event time and you will have difference in nanoseconds. You can add that difference divided by 1,000,000 to current time reference to get event time in milliseconds.
Error with calculating this can be max 0.5 milliseconds for one event. You can minimize error by changing referent times occasionally.
private long sensorTimeReference = 0l;
private long myTimeReference = 0l;
public void onSensorChanged(SensorEvent event) {
// set reference times
if(sensorTimeReference == 0l && myTimeReference == 0l) {
sensorTimeReference = event.timestamp;
myTimeReference = System.currentTimeMillis();
}
// set event timestamp to current time in milliseconds
event.timestamp = myTimeReference +
Math.round((event.timestamp - sensorTimeReference) / 1000000.0);
// some code...
}
https://source.android.com/devices/sensors/hal-interface.html#sensors_event_t
"timestamp must be synchronized with the elapsedRealtimeNano clock"
so
val timeInMills = System.currentTimeMillis() + (event.timestamp - SystemClock.elapsedRealtimeNanos()) / 1000000
The official SensorEvent#timestamp
documentation states:
[event.time is] The time in nanoseconds at which the event happened. For a given sensor, each new sensor event should be monotonically increasing using the same time base as SystemClock.elapsedRealtimeNanos().
Challenge
- Some manufacturers/devices use the
SystemClock.currentTimeNanos()
instead (e.g. Nexus 4).
Device-independent solution:
/**
* Calculates the static offset (ms) which needs to
* be added to the `event.time` (ns) to get the Unix
* timestamp of the event.
*
* @param eventTimeNanos the {@code SensorEvent.time} to be used to determine the time offset
* @return the offset in milliseconds
*/
private long eventTimeOffset(final long eventTimeNanos) {
// Capture timestamps of event reporting time
final long elapsedRealTimeMillis = SystemClock.elapsedRealtime();
final long upTimeMillis = SystemClock.uptimeMillis();
final long currentTimeMillis = System.currentTimeMillis();
// Check which timestamp the event.time is closest to the event.time
final long eventTimeMillis = eventTimeNanos / 1_000_000L;
final long elapsedTimeDiff = elapsedRealTimeMillis - eventTimeMillis;
final long upTimeDiff = upTimeMillis - eventTimeMillis;
final long currentTimeDiff = currentTimeMillis - eventTimeMillis;
// Default case (elapsedRealTime, following the documentation)
if (Math.abs(elapsedTimeDiff) <= Math.min(Math.abs(upTimeDiff), Math.abs(currentTimeDiff))) {
final long bootTimeMillis = currentTimeMillis - elapsedRealTimeMillis;
return bootTimeMillis;
}
// Other seen case (currentTime, e.g. Nexus 4)
if (Math.abs(currentTimeDiff) <= Math.abs(upTimeDiff)) {
return 0;
}
// Possible case, but unknown if actually used by manufacturers (upTime)
throw new IllegalStateException("The event.time seems to be upTime. In this case we cannot use a static offset to calculate the Unix timestamp of the event");
}
Registration time delay
- This code is independent of the latency between the
event.time
and the time at which the sensor event listener is triggered (registration time) as we only use theSystemClock
to calculate the offset. - This allows to synchronize the sensor data between multiple devices if their system time is synchronized (there are apps for this).
Regarding "Possible Case" (see code):
It's unknown if any manufacturer actually uses the
upTime
asevent.time
. Thus, we throw an exception to see if this actually ever happens.If this happens and if we calculate a static offset between
currentTime
andupTime
this would lead to time shifts when the device is in (deep) sleep again. We would need to calculate the offset dynamically for each event which is quite heavy.If this happens on devices this could be tested using: https://developer.android.com/training/monitoring-device-state/doze-standby#testing_doze_and_app_standby
I had the same problem and used ehartwell's solution. However I used System.currentTimeMillis()
instead of new Date().getTime()
.
Furthermore I found that there is an offset of sensorEvent.timeStamp
and System.nanoTime()
of maximal 300 ms, mostly < 200 ms. Depending on the needed accuracy you can ignore this difference.
If I use Boban S. solution, the difference is correct at the initialisation. However, the correct time and the time of the measurements diverge. The estimated time of the measurements is in the future.
I see three ways to get millis (Kotlin)
val millis = Date().getTime() + (event.timestamp - System.nanoTime()) / 1000000L
val millis = System.currentTimeMillis() + (event.timestamp - System.nanoTime()) / 1000000L
val millis = System.currentTimeMillis() + (event.timestamp - SystemClock.elapsedRealtimeNanos()) / 1000000L
all three deliver same result, but when I want to see diff from calculated value to current time
val diff = System.currentTimeMillis() - millis
I see 'diff' with value -359704905 ?
Log.d("diff", "" + event.timestamp + " - " + System.nanoTime())
diff: 541695268300000 - 181990403666592
diff: 541695277240000 - 181990405818592
diff: 541695286859000 - 181990411901592
diff: 541695296139000 - 181990412584592
diff: 541695305735000 - 181990415222592
So all suggested solution are not right
for me this simple way fits my needs
override fun onSensorChanged(sensorEvent: SensorEvent?) {
val millis = System.currentTimeMillis()
}
It varies for each device. It could be based on epoch, time since boot, and CPU awake time. Best approach is to read all three, then see which one the timestamp is closest to, then convert based on the offset.
SensorEvent.timestamp
is when the event happened, but it is an elapsed time since boot. It is not the time when the event happened. We want to get the actual time when the event happened from the elapsed time since the event happened.
Reference: https://developer.android.com/reference/android/hardware/SensorEvent#timestamp
- We need all the entities in a similar unit. We are taking
Millis
here. - We have three entities to use. a)
System.currentTimeMillis()
b)SystemClock.elapsedRealtime()
and c)SensorEvent.timestamp
- If we use
SystemClock.elapsedRealtimeNanos()
, then we need to convert it intoMillis
as below:
val systemCurrentTimeMillis = System.currentTimeMillis()
val systemClockElapsedRealtimeMillis = TimeUnit.NANOSECONDS.toMillis(SystemClock.elapsedRealtimeNanos())
val sensorEventTimeStampMillis = TimeUnit.NANOSECONDS.toMillis(sensorEvent.timestamp)
- We need to find the difference between the
systemCurrentTimeMillis
, andsystemClockElapsedRealtimeMillis
as below:
val currentMinusElapsedRealtimeMillis = systemCurrentTimeMillis - systemClockElapsedRealtimeMillis
- Once we find the difference, we need to add
sensorEventTimeStampMillis
to it as below:
val actualEventTimeMillis = currentMinusElapsedRealtimeMillis + sensorEventTimeStampMillis
- Then, we need to convert the result into UTC as below (I am using
Joda Time
):
val actualEventTimeUtc = DateTime(actualEventTimeMillis, DateTimeZone.UTC)
The actualEventTimeUtc
is the absolute time when the event happened.
Another way to understand it is:
Suppose the sensor reports an event in onSensorChanged.
We find that the current time is: 13 PM. In other words, the reporting time is 13 PM and it is not the time when the actual event happened.
The SystemClock.elapsedRealtime()
says that it has been running since last 30 hours. In other words, it started 30 hours before from the current time.
So, we subtract the 30 hours from the current time to get the time when the sensor started. So, we get 7 AM of the previous day.
The SensorEvent.timestamp
says that the event happened after 28 hours of the SystemClock.elapsedRealtime().
Hence, we add 28 hours to the 7 AM of the previous day. So, we get 11 AM of the current day and it is the actual time when event happened.
精彩评论