Google Health API 提供專屬的匯總端點,可將健康記錄分組並彙整成時間範圍。請使用匯總端點,透過經過核對的資料串流計算指標 (例如總計、平均值、最小值和最大值),而不是在用戶端擷取及加總個別原始記錄:
rollUp端點會使用可設定的時間範圍長度 (以秒為單位,windowSize),以世界標準時間 (UTC) 匯總實體時間間隔內的資料點。dailyRollUp端點會使用與使用者當地時鐘相關的民用時間,匯總一或多個日曆日 (windowSizeDays) 的資料點。
這兩個端點會自動協調連結裝置間重疊的資料點,並排除支援佩戴偵測的穿戴式裝置資料類型中,未佩戴裝置期間的資料。
比較匯總端點
根據應用程式分組及顯示時間序列健康指標的方式,選擇對應的匯總端點:
| 功能 | rollUp 個端點 |
dailyRollUp 個端點 |
|---|---|---|
| HTTP 要求 | POST https://health.googleapis.com/v4/users/me/dataTypes/data-type/dataPoints:rollUp |
POST https://health.googleapis.com/v4/users/me/dataTypes/data-type/dataPoints:dailyRollUp |
| 時間表示法 | 世界標準時間的實際時間 (startTime 和 endTime,採用 RFC 3339 格式)。 |
民用時間 (start 和 end 為 CivilDateTime 物件)。 |
| Window 參數 | windowSize (必要字串,時間長度以秒為單位,下限為 "1s")。 |
windowSizeDays (選用,整數,代表天數,預設為 1)。 |
| 回應物件 | RollupDataPoint |
DailyRollupDataPoint |
| 回覆排序 | 依時間倒序排列 (最新視窗排在最前面)。 | 依時間倒序排列 (最新視窗排在最前面)。 |
| 適用情境 | 當日圖表、每小時或每分鐘直方圖,以及固定時間長度的世界標準時間分析。 | 每日資訊主頁、多日趨勢和摘要,會考量時區旅行或日光節約時間。 |
這兩個端點都會根據資料類型,強制執行查詢範圍上限:
calories-in-heart-rate-zone、heart-rate、active-minutes和total-calories的查詢範圍上限為 14 天。- 所有其他支援的資料類型,查詢範圍上限為 90 天。
如要查看哪些資料類型支援 rollup 和 dailyRollup,請參閱 Google Health API 資料類型參考資料。
依實體時間間隔匯總
使用 rollUp 端點,依實際時間 range (世界標準時間) 匯總資料點,並依時間範圍長度 (以秒為單位,windowSize) 分組。
呼叫 rollUp 端點時,請提供 JSON 要求主體,其中包含左閉右開的 range (包含 startTime,不包含 endTime) 和 windowSize。請留意下列 windowSize 規定:
windowSize持續時間必須至少為 1 秒 ("1s")。API 會拒絕小於一秒、零或負值的持續時間,並傳回400 Bad Request(INVALID_ROLLUP_WINDOW) 錯誤。- 為避免匯總資料在子值區中分布不均,請選擇等於或大於資料類型基礎儲存解析度的
windowSize(例如 1 分鐘步數間隔的"60s")。詳情請參閱「匯總時間範圍和儲存空間解析度」。
舉例來說,下列要求會以 1 分鐘為間隔 (60s) 匯總步數:
要求
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:rollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"startTime": "2026-02-17T17:00:00Z",
"endTime": "2026-02-17T17:59:59Z"
},
"windowSize": "60s"
}回應
{
"rollupDataPoints": [
{
"startTime": "2026-02-17T17:55:00Z",
"endTime": "2026-02-17T17:56:00Z",
"steps": {
"countSum": "72"
}
},
{
"startTime": "2026-02-17T17:54:00Z",
"endTime": "2026-02-17T17:55:00Z",
"steps": {
"countSum": "85"
}
},
...
]
}依日曆日期匯總
使用 dailyRollUp 端點匯總單一或多個日曆日的資料 (windowSizeDays)。請在要求主體中提供閉開區間的民用時間 range (start 和 end)。端點會根據資料類型,傳回匯總值,例如每個民用時間範圍的總和或平均值。
由於 dailyRollUp 會使用每個資料點記錄的世界標準時間偏移量,在民用時間上運作,因此會自動協調因日光節約時間轉換或跨時區旅行而導致的可變日長。
舉例來說,下列要求會匯總單一公曆日 (windowSizeDays: 1) 的步數:
要求
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:dailyRollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"start": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
},
"end": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59,
"nanos": 0
}
}
},
"windowSizeDays": 1
}回應
{
"rollupDataPoints": [
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "3822"
}
}
]
}依資料來源系列匯總
rollUp 和 dailyRollUp 都在 JSON 要求主體中接受選用的 dataSourceFamily 欄位,可將匯總範圍限制在特定來源群組:
users/me/dataSourceFamilies/all-sources選項 (預設) 會匯總所有已註冊第一方和第三方來源的對帳資料。users/me/dataSourceFamilies/google-wearables選項會匯總 Google 和 Fitbit 穿戴式追蹤器裝置記錄的資料,但不包括手動記錄和手機估算的資料。users/me/dataSourceFamilies/google-sources選項會匯總 Google 和 Fitbit 第一方來源的資料,包括穿戴式追蹤器、「健康資料同步」和第一方應用程式中的手動輸入資料。
如需完整的參數規定,以及要求和回應範例,請參閱「篩選資料」指南中的「依資料來源系列篩選」。
匯總時間範圍和儲存空間解析度
雖然 rollUp 端點接受任何 1 秒 ("1s") 以上的 windowSize,但不同資料類型會以不同的取樣率或間隔時間,在基礎儲存空間中記錄及保留測量結果。舉例來說,穿戴式裝置的體能活動指標 (例如 steps、distance、active-minutes 和 active-energy-burned) 通常會以 1 分鐘 (60s) 為間隔記錄。
下表列出基礎儲存空間解析度,以及常見資料類型的建議 windowSize 最小值:
| 儲存空間解析度 | 建議的基本需求:windowSize |
資料類型 |
|---|---|---|
1 秒 (1s) |
"1s" |
heart-rate |
1 分鐘 (60s) |
"60s" |
active-energy-burned、active-minutes、active-zone-minutes、altitude、calories-in-heart-rate-zone、distance、floors、steps、time-in-heart-rate-zone、total-calories |
匯總間隔資料類型時,rollUp 端點會將每個記錄的資料點放入包含資料點 startTime 的值區。API 不會將間隔資料切片、內插或分配到子間隔值區。
如果指定的 windowSize 小於基礎資料儲存間隔 (例如,要求以 1 分鐘間隔儲存的 steps 10 秒視窗):
- 第一個符合時間間隔
startTime的子值區 (例如10:00:00到10:00:10) 會收到整分鐘的累計計數 (例如該分鐘記錄的所有 100 步)。 - 同一分鐘內剩餘的子值區 (
10:00:10到10:00:20、10:00:20到10:00:30等) 不會收到任何資料點,因為這些時間範圍內沒有任何間隔開始。
這會產生尖峰資料,其中整個間隔的值都集中在第一個子視窗中,如圖 1 所示。
為取得平均分布且有意義的匯總資料,請一律將 windowSize 設為等於或大於目標資料類型的基礎儲存解析度 (例如 steps 的 "60s" 或更大)。如要瞭解各資料類型的儲存解析度和建議的最小匯總時間範圍,請參閱 Google Health API 資料類型參考資料。
範圍不是視窗大小的倍數時,如何分桶
如果要求的範圍不是 windowSize (或 windowSizeDays) 的整數倍,則最後一個時間區間會在範圍的上限端點截斷,且涵蓋的時間長度會短於時間範圍大小。API 會接受您的要求,不會進行修改,也不會執行四捨五入、時間移位或資料內插。
為涵蓋整個要求的範圍,API 會使用無條件進位除法,計算匯總視窗總數:
Number of windows = ceiling(Range duration / Window size)
每個值區都會從範圍的開頭依序開始。如果新增另一個完整大小的視窗會超出要求的結束時間,則最後一個視窗會在範圍結束時間截斷 (限制)。
分桶機制
如果您要求匯總不可分割的範圍,API 會套用下列規則:
- 分桶作業會從要求的範圍 (
range.startTime或range.start) 起點開始,並依據視窗大小 (windowSize或windowSizeDays) 向前推進。 - 最後一個時間區間會固定在要求範圍的結尾 (
range.endTime或range.end),涵蓋的時間長度會比要求的時間範圍大小短。 - 傳回的
RollupDataPoint或DailyRollupDataPoint物件包含明確的開始和結束時間戳記,可用於檢查截斷值區的實際時間長度。 - 由於 API 會依時間倒序 (最新優先) 傳回匯總資料,因此最後一個時間值區 (截斷值區) 會顯示為傳回清單中的第一個元素 (
index 0)。
圖 2 說明 API 如何從 range.startTime 向前分組不可分割的範圍、將最終分組限制在 range.endTime,並依時間倒序傳回產生的分組。
範例:12 分鐘範圍,時間範圍為 5 分鐘
假設用戶端要求在 12 分鐘範圍內匯總,並設定 5 分鐘的 windowSize ("300s"):
range.startTime的值是10:00:00Z。range.endTime值為10:12:00Z,總時間長度為 12 分鐘。windowSize值為"300s"(5 分鐘)。
由於 12 分鐘並非 5 分鐘 (12 = 5 * 2 + 2) 的整數倍,API 會將時間範圍數量計算為 ceiling(12 / 5) = 3。這會產生三個時間順序值區:
| 值區 | 間隔 | 時間長度 | 效期狀態 |
|---|---|---|---|
| Bucket 1 | [10:00:00Z, 10:05:00Z) |
5 分鐘 | 全視窗 |
| Bucket 2 | [10:05:00Z, 10:10:00Z) |
5 分鐘 | 全視窗 |
| Bucket 3 | [10:10:00Z, 10:12:00Z) |
2 分鐘 | 在 range.endTime 截斷 |
對匯總值的影響
由於最後一個時間範圍的時間較短,因此在截斷的值區中,累加指標 (例如步數總和或計數) 會因時間範圍較短而較低。
如果使用者在這 12 分鐘內以每分鐘 100 步的穩定速度行走,則值區會包含下列總計:
- 區間 1 (
10:00:00Z至10:05:00Z) 記錄了 500 步 (5 分鐘,每分鐘 100 步)。 - 區間 2 (
10:05:00Z至10:10:00Z) 記錄了 500 步 (5 分鐘,每分鐘 100 步)。 - Bucket 3 (
10:10:00Z至10:12:00Z) 記錄 200 步 (2 分鐘,每分鐘 100 步)。
Bucket 3 的步數較低 (200 步),是因為截斷時間範圍只有 2 分鐘,而非使用者活動量下降。繪製或分析這類資料時,請使用各個值區的明確時間長度,將計數正規化,以免呈現誤導性的使用者活動下降趨勢。
圖 3 比較了三個值區的原始累加步數總計 (countSum) 與時間長度正規化比率。
顯示排序的 API 回應範例
由於 API 會依時間倒序傳回結果,因此截斷的值區會顯示為傳回清單中的第一個元素:
{
"rollupDataPoints": [
{
"startTime": "2026-08-20T10:10:00Z",
"endTime": "2026-08-20T10:12:00Z",
"steps": {
"countSum": "200"
}
},
{
"startTime": "2026-08-20T10:05:00Z",
"endTime": "2026-08-20T10:10:00Z",
"steps": {
"countSum": "500"
}
},
{
"startTime": "2026-08-20T10:00:00Z",
"endTime": "2026-08-20T10:05:00Z",
"steps": {
"countSum": "500"
}
}
]
}