Reputation: 1621
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 readable date time format.Thanks in advance
How can i convert SensorEvent timestamp to unix timestamp?
Upvotes: 35
Views: 30656
Reputation: 586
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
Millis
here.System.currentTimeMillis()
b) SystemClock.elapsedRealtime()
and c) SensorEvent.timestamp
SystemClock.elapsedRealtimeNanos()
, then we need to convert it into Millis
as below:val systemCurrentTimeMillis = System.currentTimeMillis()
val systemClockElapsedRealtimeMillis = TimeUnit.NANOSECONDS.toMillis(SystemClock.elapsedRealtimeNanos())
val sensorEventTimeStampMillis = TimeUnit.NANOSECONDS.toMillis(sensorEvent.timestamp)
systemCurrentTimeMillis
, and systemClockElapsedRealtimeMillis
as below:val currentMinusElapsedRealtimeMillis = systemCurrentTimeMillis - systemClockElapsedRealtimeMillis
sensorEventTimeStampMillis
to it as below:val actualEventTimeMillis = currentMinusElapsedRealtimeMillis + sensorEventTimeStampMillis
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.
Upvotes: 2
Reputation: 3757
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
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
event.time
and the time at which the sensor event listener is triggered (registration time) as we only use the SystemClock
to calculate the offset.Regarding "Possible Case" (see code):
It's unknown if any manufacturer actually uses the upTime
as event.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
and upTime
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
Upvotes: 4
Reputation: 51
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
Upvotes: 5
Reputation: 810
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.
Upvotes: 1
Reputation: 17763
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()
}
Upvotes: 1
Reputation: 851
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.
Upvotes: 1
Reputation: 1662
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...
}
Upvotes: 5
Reputation: 1677
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.
Upvotes: 41