Использование часового пояса API GoogleFit REST игнорируется при запросе агрегированных данных, сгруппированных по периодам времени - PullRequest
0 голосов
/ 31 мая 2019

Я объединяю эти источники данных:

$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); Я все ещезастрял, получая те же точные данные.

Данные никогда не совпадают точно, что они показаны на устройстве.Кто-нибудь был в состоянии соответствовать этому отлично?Я думал о том, чтобы собрать эти данные из сегментов деятельности, но я не уверен, что это будет работать правильно.

Ответы [ 2 ]

0 голосов
/ 10 июня 2019

Я только что сильно изменил этот код, но у меня все еще есть проблемы.

Пользователь, с которым я тестирую, находится в Asia/Kolkata часовом поясе.

Они отправлены на скриншотеих расстояние GoogleFit для просмотра за неделю ежедневной сводки.

Снимок экрана здесь

Чтобы суммировать данные на скриншоте:

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;
    }

Любое пониманиекак правильно интерпретировать эти данные было бы неоценимо.

0 голосов
/ 03 июня 2019

Документация для этого не совсем ясна.

Периоды агрегации определяются startTimeMillis и bucketByTime.period или bucketByTime.durationMillis.По сути, время начала увеличивается на период / продолжительность, пока не достигнет (или не превысит) endTimeMillis;если конечное время окончания периода после endTimeMillis, оно просто ограничено этим временем.

bucketByTime.period.timeZoneId на самом деле имеет относительно небольшое влияние на границы сегмента: оно просто используется для создания «дополнительных дней», расчет «плюс недели», «плюс месяцы» в правильном часовом поясе, для случаев, когда «день» не длится 24 часа и т. д. Это, вероятно, будет действительно иметь значение только при изменениях летнего времени.

Итак, если вы хотите, чтобы начальное и конечное время были выровнены с определенным временем дня, вам необходимо указать выравнивание самостоятельно через поле startTimeMillis.

Это может восприниматься как раздражающая деталь, котораявам не нужно иметь дело с этим, но он дает вам гибкость в выборе времени, а не, скажем, навязывания вам «полуночи» (или, точнее, начала дня).

...