请求按时间段分桶的聚合数据时,将忽略使用 GoogleFit REST API 时区
Using the GoogleFit REST API timezone is ignored when making a request for aggregate data bucketed by time period
我结合了这些数据源:
$steps = static::getDataByAggregate('derived:com.google.step_count.delta:com.google.android.gms:estimated_steps', 'com.google.step_count.delta', $period['Start'], $period['End']);
$distance = static::getDataByAggregate('derived:com.google.distance.delta:com.google.android.gms:merge_distance_delta', 'com.google.distance.delta', $period['Start'], $period['End']);
$calories = static::getDataByAggregate('derived:com.google.calories.expended:com.google.android.gms:merge_calories_expended', 'com.google.calories.expended', $period['Start'], $period['End']);
$activeMinutes = static::getDataByAggregate('derived:com.google.active_minutes:com.google.android.gms:merge_active_minutes', 'com.google.active_minutes', $period['Start'], $period['End']);
$aggregates = array_merge($aggregates, static::mergeAggregates([
'steps' => $steps,
'distance' => $distance,
'calories' => $calories,
'activeMinutes' => $activeMinutes,
]));
所以这个函数运行实际的聚合拉动。
/**
* Gets aggregated data by date for a given timerange.
*
* @see https://developers.google.com/fit/rest/v1/data-types#data_types_for_aggregate_data
*
* @param string $sourceId
* @param string $dataType
* @param int $start UTC unix timestamp
* @param int $end UTC unix timestamp
* @return array Array with values by data type, the date is the key.
*/
public static function getDataByAggregate($sourceId, $dataType, $start, $end)
{
if (!in_array($sourceId, static::$availableSources)) {
return;
}
$time = new \Google_Service_Fitness_BucketByTime();
$aggregateBy = new \Google_Service_Fitness_AggregateBy();
$bucketByTimePeriod = new \Google_Service_Fitness_BucketByTimePeriod();
$bucketByTimePeriod->setValue(1);
$bucketByTimePeriod->setType('day');
$bucketByTimePeriod->setTimeZoneId(static::$aggregateTimezone);
$time->setPeriod($bucketByTimePeriod);
//$time->setDurationMillis("86400000");
$aggregateBy->setDataTypeName($dataType);
$aggregateBy->setDataSourceId($sourceId);
$rx = new \Google_Service_Fitness_AggregateRequest();
$rx->startTimeMillis = $start / 1000000;
$rx->endTimeMillis = $end / 1000000;
$rx->setAggregateBy([$aggregateBy]);
$rx->setBucketByTime($time);
$aggr = static::users_dataset_aggregate('me', $rx);
$data = [];
$buckets = $aggr->getBucket();
foreach ($buckets as $bucket) {
$dataset = $bucket->getDataset();
foreach ($dataset[0]->getPoint() as $point) {
$value = $point->getValue()[0]->getIntVal();
if ($value === null) {
$value = $point->getValue()[0]->getFpVal();
}
$Segment = [
'Data'=> $value,
'StartTime' => intval($point->startTimeNanos / 1000000 / 1000),
'EndTime' => intval($point->endTimeNanos / 1000000 / 1000),
];
/**
* Apparently the step, distance, and calorie count in the app is pegged to UTC no matter what timezone.
*/
$Start = new DateTime('now', new DateTimeZone('UTC'));
$End = new DateTime('now', new DateTimeZone('UTC'));
$Start->setTimestamp($Segment['StartTime']);
$End->setTimestamp($Segment['EndTime']);
$data[$Start->format('Y-m-d')] = $Segment['Data'];
}
}
return $data;
}
无论我进入哪个时区$bucketByTimePeriod->setTimeZoneId(static::$aggregateTimezone);
,我仍然无法获得完全相同的数据。
数据永远不会与设备上显示的完全匹配。有没有人能够完美匹配它?我正在考虑从 activity 段中提取这些数据,但我不确定这是否能正常工作。
这个 documentation 根本不清楚。
聚合时间段由 startTimeMillis
和 bucketByTime.period
或 bucketByTime.durationMillis
决定。基本上,开始时间会增加 period/duration,直到达到(或超过)endTimeMillis
;如果最终桶结束时间在 endTimeMillis
之后,它只是被限制到那个时间。
bucketByTime.period.timeZoneId
实际上对桶边界的影响相对较小:它只是用于在正确的时区进行 "plus days"、"plus weeks"、"plus months" 计算,对于 "a day" 不是 24 小时等的情况。这可能只会真正影响夏令时的变化。
因此,如果您希望开始时间和结束时间与一天中的特定时间对齐,您需要通过 startTimeMillis
字段自行指定对齐方式。
这可能被认为是您不应该处理的恼人细节,但它确实让您可以灵活地选择桶时间,而不是说 "midnight"(或者,更准确地说,一天的开始)强加给你。
我刚刚更改了很多代码,但我仍然遇到问题。
我正在测试的用户在 Asia/Kolkata
时区。
他们发送了 GoogleFit 距离的屏幕截图,用于每日摘要的周视图。
Screenshot here
总结截图中的数据:
05-13 07.26 KM
05-14 07.60 KM
05-15 00.83 KM
05-16 11.72 KM
05-17 05.07 KM
现在这是我实际得到的:
1557685800 = Monday May 13, 2019 00:00:00 (am) in time zone Asia/Kolkata (IST)
1558117799 = Friday May 17, 2019 23:59:59 (pm) in time zone Asia/Kolkata (IST)
"com.google.distance.delta"
array:3 [
"Data" => 7260.1155674458
"StartTime" => 1557726389
"EndTime" => 1557765900
]
array:3 [
"Data" => 7590.043877244
"StartTime" => 1557795622
"EndTime" => 1557852687
]
array:3 [
"Data" => 831.04253411293
"StartTime" => 1557896356
"EndTime" => 1557932355
]
array:3 [
"Data" => 11661.883238077
"StartTime" => 1557945060
"EndTime" => 1558024560
]
array:3 [
"Data" => 6889.3030343056
"StartTime" => 1558067629
"EndTime" => 1558110540
]
所以你可以看到它很接近但仍然关闭。
这是我的新代码:
/**
* Gets aggregated data by date for a given timerange.
*
* @see https://developers.google.com/fit/rest/v1/data-types#data_types_for_aggregate_data
*
* @param string $sourceId
* @param string $dataType
* @param int $start UTC unix timestamp
* @param int $end UTC unix timestamp
* @return array Array with values by data type, the date is the key.
*/
public static function getDataByAggregate($sourceId, $dataType, $start, $end)
{
if (!in_array($sourceId, static::$availableSources)) {
return;
}
$dtz = new DateTimeZone(static::$aggregateTimezone);
$aggregateBy = new \Google_Service_Fitness_AggregateBy();
$time = new \Google_Service_Fitness_BucketByTime();
$time->setDurationMillis("86400000");
/*
$bucketByTimePeriod = new \Google_Service_Fitness_BucketByTimePeriod();
$bucketByTimePeriod->setValue(1);
$bucketByTimePeriod->setType('day');
$bucketByTimePeriod->setTimeZoneId(static::$aggregateTimezone);
$time->setPeriod($bucketByTimePeriod);
*/
$aggregateBy->setDataTypeName($dataType);
$aggregateBy->setDataSourceId($sourceId);
$rx = new \Google_Service_Fitness_AggregateRequest();
$rx->startTimeMillis = $start * 1000;
$rx->endTimeMillis = $end * 1000;
$rx->setAggregateBy([$aggregateBy]);
$rx->setBucketByTime($time);
$aggr = static::users_dataset_aggregate('me', $rx);
if ($dataType==='com.google.distance.delta') {
dump($start,$end);
dump($dataType);
}
$data = [];
$buckets = $aggr->getBucket();
foreach ($buckets as $bucket) {
$dataset = $bucket->getDataset();
foreach ($dataset[0]->getPoint() as $point) {
$value = $point->getValue()[0]->getIntVal();
if ($value === null) {
$value = $point->getValue()[0]->getFpVal();
}
$Segment = [
'Data'=> $value,
'StartTime' => intval($point->startTimeNanos / 1000000 / 1000),
'EndTime' => intval($point->endTimeNanos / 1000000 / 1000),
];
if($dataType==='com.google.distance.delta') {
dump($Segment);
}
$SegmentStart = new DateTime('@'.$Segment['StartTime'], $dtz);
$SegmentEnd = new DateTime('@'.$Segment['EndTime'], $dtz);
$SegmentStart->setTimezone($dtz);
$SegmentEnd->setTimezone($dtz);
$data[$SegmentStart->format('Y-m-d')] = $Segment['Data'];
}
}
return $data;
}
任何关于如何正确解释这些数据的见解都将是无价的。
我结合了这些数据源:
$steps = static::getDataByAggregate('derived:com.google.step_count.delta:com.google.android.gms:estimated_steps', 'com.google.step_count.delta', $period['Start'], $period['End']);
$distance = static::getDataByAggregate('derived:com.google.distance.delta:com.google.android.gms:merge_distance_delta', 'com.google.distance.delta', $period['Start'], $period['End']);
$calories = static::getDataByAggregate('derived:com.google.calories.expended:com.google.android.gms:merge_calories_expended', 'com.google.calories.expended', $period['Start'], $period['End']);
$activeMinutes = static::getDataByAggregate('derived:com.google.active_minutes:com.google.android.gms:merge_active_minutes', 'com.google.active_minutes', $period['Start'], $period['End']);
$aggregates = array_merge($aggregates, static::mergeAggregates([
'steps' => $steps,
'distance' => $distance,
'calories' => $calories,
'activeMinutes' => $activeMinutes,
]));
所以这个函数运行实际的聚合拉动。
/**
* Gets aggregated data by date for a given timerange.
*
* @see https://developers.google.com/fit/rest/v1/data-types#data_types_for_aggregate_data
*
* @param string $sourceId
* @param string $dataType
* @param int $start UTC unix timestamp
* @param int $end UTC unix timestamp
* @return array Array with values by data type, the date is the key.
*/
public static function getDataByAggregate($sourceId, $dataType, $start, $end)
{
if (!in_array($sourceId, static::$availableSources)) {
return;
}
$time = new \Google_Service_Fitness_BucketByTime();
$aggregateBy = new \Google_Service_Fitness_AggregateBy();
$bucketByTimePeriod = new \Google_Service_Fitness_BucketByTimePeriod();
$bucketByTimePeriod->setValue(1);
$bucketByTimePeriod->setType('day');
$bucketByTimePeriod->setTimeZoneId(static::$aggregateTimezone);
$time->setPeriod($bucketByTimePeriod);
//$time->setDurationMillis("86400000");
$aggregateBy->setDataTypeName($dataType);
$aggregateBy->setDataSourceId($sourceId);
$rx = new \Google_Service_Fitness_AggregateRequest();
$rx->startTimeMillis = $start / 1000000;
$rx->endTimeMillis = $end / 1000000;
$rx->setAggregateBy([$aggregateBy]);
$rx->setBucketByTime($time);
$aggr = static::users_dataset_aggregate('me', $rx);
$data = [];
$buckets = $aggr->getBucket();
foreach ($buckets as $bucket) {
$dataset = $bucket->getDataset();
foreach ($dataset[0]->getPoint() as $point) {
$value = $point->getValue()[0]->getIntVal();
if ($value === null) {
$value = $point->getValue()[0]->getFpVal();
}
$Segment = [
'Data'=> $value,
'StartTime' => intval($point->startTimeNanos / 1000000 / 1000),
'EndTime' => intval($point->endTimeNanos / 1000000 / 1000),
];
/**
* Apparently the step, distance, and calorie count in the app is pegged to UTC no matter what timezone.
*/
$Start = new DateTime('now', new DateTimeZone('UTC'));
$End = new DateTime('now', new DateTimeZone('UTC'));
$Start->setTimestamp($Segment['StartTime']);
$End->setTimestamp($Segment['EndTime']);
$data[$Start->format('Y-m-d')] = $Segment['Data'];
}
}
return $data;
}
无论我进入哪个时区$bucketByTimePeriod->setTimeZoneId(static::$aggregateTimezone);
,我仍然无法获得完全相同的数据。
数据永远不会与设备上显示的完全匹配。有没有人能够完美匹配它?我正在考虑从 activity 段中提取这些数据,但我不确定这是否能正常工作。
这个 documentation 根本不清楚。
聚合时间段由 startTimeMillis
和 bucketByTime.period
或 bucketByTime.durationMillis
决定。基本上,开始时间会增加 period/duration,直到达到(或超过)endTimeMillis
;如果最终桶结束时间在 endTimeMillis
之后,它只是被限制到那个时间。
bucketByTime.period.timeZoneId
实际上对桶边界的影响相对较小:它只是用于在正确的时区进行 "plus days"、"plus weeks"、"plus months" 计算,对于 "a day" 不是 24 小时等的情况。这可能只会真正影响夏令时的变化。
因此,如果您希望开始时间和结束时间与一天中的特定时间对齐,您需要通过 startTimeMillis
字段自行指定对齐方式。
这可能被认为是您不应该处理的恼人细节,但它确实让您可以灵活地选择桶时间,而不是说 "midnight"(或者,更准确地说,一天的开始)强加给你。
我刚刚更改了很多代码,但我仍然遇到问题。
我正在测试的用户在 Asia/Kolkata
时区。
他们发送了 GoogleFit 距离的屏幕截图,用于每日摘要的周视图。
Screenshot here
总结截图中的数据:
05-13 07.26 KM
05-14 07.60 KM
05-15 00.83 KM
05-16 11.72 KM
05-17 05.07 KM
现在这是我实际得到的:
1557685800 = Monday May 13, 2019 00:00:00 (am) in time zone Asia/Kolkata (IST)
1558117799 = Friday May 17, 2019 23:59:59 (pm) in time zone Asia/Kolkata (IST)
"com.google.distance.delta"
array:3 [
"Data" => 7260.1155674458
"StartTime" => 1557726389
"EndTime" => 1557765900
]
array:3 [
"Data" => 7590.043877244
"StartTime" => 1557795622
"EndTime" => 1557852687
]
array:3 [
"Data" => 831.04253411293
"StartTime" => 1557896356
"EndTime" => 1557932355
]
array:3 [
"Data" => 11661.883238077
"StartTime" => 1557945060
"EndTime" => 1558024560
]
array:3 [
"Data" => 6889.3030343056
"StartTime" => 1558067629
"EndTime" => 1558110540
]
所以你可以看到它很接近但仍然关闭。
这是我的新代码:
/**
* Gets aggregated data by date for a given timerange.
*
* @see https://developers.google.com/fit/rest/v1/data-types#data_types_for_aggregate_data
*
* @param string $sourceId
* @param string $dataType
* @param int $start UTC unix timestamp
* @param int $end UTC unix timestamp
* @return array Array with values by data type, the date is the key.
*/
public static function getDataByAggregate($sourceId, $dataType, $start, $end)
{
if (!in_array($sourceId, static::$availableSources)) {
return;
}
$dtz = new DateTimeZone(static::$aggregateTimezone);
$aggregateBy = new \Google_Service_Fitness_AggregateBy();
$time = new \Google_Service_Fitness_BucketByTime();
$time->setDurationMillis("86400000");
/*
$bucketByTimePeriod = new \Google_Service_Fitness_BucketByTimePeriod();
$bucketByTimePeriod->setValue(1);
$bucketByTimePeriod->setType('day');
$bucketByTimePeriod->setTimeZoneId(static::$aggregateTimezone);
$time->setPeriod($bucketByTimePeriod);
*/
$aggregateBy->setDataTypeName($dataType);
$aggregateBy->setDataSourceId($sourceId);
$rx = new \Google_Service_Fitness_AggregateRequest();
$rx->startTimeMillis = $start * 1000;
$rx->endTimeMillis = $end * 1000;
$rx->setAggregateBy([$aggregateBy]);
$rx->setBucketByTime($time);
$aggr = static::users_dataset_aggregate('me', $rx);
if ($dataType==='com.google.distance.delta') {
dump($start,$end);
dump($dataType);
}
$data = [];
$buckets = $aggr->getBucket();
foreach ($buckets as $bucket) {
$dataset = $bucket->getDataset();
foreach ($dataset[0]->getPoint() as $point) {
$value = $point->getValue()[0]->getIntVal();
if ($value === null) {
$value = $point->getValue()[0]->getFpVal();
}
$Segment = [
'Data'=> $value,
'StartTime' => intval($point->startTimeNanos / 1000000 / 1000),
'EndTime' => intval($point->endTimeNanos / 1000000 / 1000),
];
if($dataType==='com.google.distance.delta') {
dump($Segment);
}
$SegmentStart = new DateTime('@'.$Segment['StartTime'], $dtz);
$SegmentEnd = new DateTime('@'.$Segment['EndTime'], $dtz);
$SegmentStart->setTimezone($dtz);
$SegmentEnd->setTimezone($dtz);
$data[$SegmentStart->format('Y-m-d')] = $Segment['Data'];
}
}
return $data;
}
任何关于如何正确解释这些数据的见解都将是无价的。