首页 > 解决方案 > 对按时间段分桶的聚合数据发出请求时,将忽略使用 GoogleFit REST API 时区

问题描述

我结合了这些数据源:

$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);仍然无法获得相同的确切数据。

数据永远不会与设备上显示的完全匹配。有没有人能完美匹配?我正在考虑将这些数据从活动段中提取出来,但我不确定这是否能正常工作。

标签: phpgoogle-fitgoogle-fit-sdk

解决方案


这方面的文档根本不清楚。

聚合时间段由startTimeMillisbucketByTime.period或确定bucketByTime.durationMillis。基本上,开始时间会增加周期/持续时间,直到达到(或超过)endTimeMillis; 如果最终的桶结束时间在 之后endTimeMillis,它只是被限制到那个时间。

bucketByTime.period.timeZoneId实际上对存储桶边界的影响相对较小:它只是用于在正确的时区中进行“加天”、“加周”、“加月”计算,适用于“一天”不是 24 小时长的情况等等。这可能只会在夏令时更改方面真正有所作为。

因此,如果您希望开始和结束时间与一天中的特定时间对齐,您需要通过该startTimeMillis字段自己指定对齐方式。

这可能被视为您不应该处理的令人讨厌的细节,但它确实使您可以灵活地选择时间段,而不是说“午夜”(或者更准确地说,是一天的开始) ) 强加给你。


推荐阅读