【发布时间】:2011-03-31 13:38:07
【问题描述】:
我目前正在开发一个 android 应用程序。我必须用事件时间记录加速度计传感器事件坐标。我得到了像“3497855005850”这样的传感器事件时间戳,但我无法将事件时间戳转换为用户可读的日期时间格式。提前致谢
如何将 SensorEvent 时间戳转换为 unix 时间戳?
【问题讨论】:
标签: android
我目前正在开发一个 android 应用程序。我必须用事件时间记录加速度计传感器事件坐标。我得到了像“3497855005850”这样的传感器事件时间戳,但我无法将事件时间戳转换为用户可读的日期时间格式。提前致谢
如何将 SensorEvent 时间戳转换为 unix 时间戳?
【问题讨论】:
标签: android
https://source.android.com/devices/sensors/hal-interface.html#sensors_event_t
“时间戳必须与 elapsedRealtimeNano 时钟同步”
所以
val timeInMills = System.currentTimeMillis() + (event.timestamp - SystemClock.elapsedRealtimeNanos()) / 1000000
【讨论】:
官方SensorEvent#timestampdocumentation表示:
[event.time is] 事件发生的时间(以纳秒为单位)。对于给定的传感器,每个新的传感器事件都应该单调递增使用与 SystemClock.elapsedRealtimeNanos() 相同的时基。
挑战
SystemClock.currentTimeNanos()(例如 Nexus 4)。独立于设备的解决方案:
/**
* 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");
}
注册时间延迟
event.time 与触发传感器事件侦听器的时间(注册时间)之间的延迟无关,因为我们仅使用SystemClock 来计算偏移量。关于“可能的情况”(见代码):
尚不清楚是否有制造商将upTime 用作event.time。因此,我们抛出一个异常来看看这是否真的发生过。
如果发生这种情况,并且如果我们计算 currentTime 和 upTime 之间的静态偏移量,这将导致设备再次处于(深度)睡眠状态时发生时间偏移。我们需要为每个非常重的事件动态计算偏移量。
如果在设备上发生这种情况,可以使用以下方法进行测试:https://developer.android.com/training/monitoring-device-state/doze-standby#testing_doze_and_app_standby
【讨论】:
每个设备都不同。它可以基于纪元、自启动以来的时间和 CPU 唤醒时间。最好的方法是读取所有三个,然后查看时间戳最接近哪一个,然后根据偏移量进行转换。
【讨论】:
我看到了三种获取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
所有三个都提供相同的结果,但是当我想查看计算值与当前时间的差异时
val diff = System.currentTimeMillis() - millis
我看到 'diff' 的值为 -359704905 ?
Log.d("diff", "" + event.timestamp + " - " + System.nanoTime())
差异:541695268300000 - 181990403666592
差异:541695277240000 - 181990405818592
差异:541695286859000 - 181990411901592
差异:541695296139000 - 181990412584592
差异:541695305735000 - 181990415222592
所以所有建议的解决方案都不正确
对我来说,这种简单的方法适合我的需要
override fun onSensorChanged(sensorEvent: SensorEvent?) {
val millis = System.currentTimeMillis()
}
【讨论】:
您可以在 onSensorChanged(SensorEvent) 函数中设置参考时间变量。
当前时间和事件时间的参考。当事件到达时,从事件时间中减去传感器参考时间,您将有纳秒的差异。您可以将该差除以 1,000,000 与当前时间参考相加,以获取以毫秒为单位的事件时间。
一个事件的计算误差最大为 0.5 毫秒。您可以通过偶尔更改参考时间来最大程度地减少错误。
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...
}
【讨论】:
传感器时间戳实际上是纳秒的正常运行时间,不是以纳秒为单位的系统时间。见SensorEvent.timestamp to absolute (utc) timestamp?。
理论上,您可以使用以下方法将传感器时间戳转换为以毫秒为单位的时间:
long timeInMillis = (new Date()).getTime()
+ (sensorEvent.timestamp - System.nanoTime()) / 1000000L;
您甚至可以将 (new Date()).getTime() 调用与两个 System.nanoTime() 调用括起来,并对它们进行平均以更接近实际偏移量。
然后您可以将传感器时间格式化为日期和时间。
【讨论】:
sensorEvent.timestamp 似乎包含准确的时间戳(以纳秒为单位)。这似乎是无证的,尽管它非常重要!