mirror of
https://github.com/This-weiyuqing/mi-fitness-health.git
synced 2026-10-18 03:03:49 +08:00
fix: preserve Mi Fitness local timezone offsets
This commit is contained in:
1 parent
eef795672d
commit
c901e712d7
2 files changed
+54
-31
No files matched your search
@@ -6,7 +6,7 @@ import os
|
||||
import struct
|
||||
from collections import defaultdict
|
||||
from collections.abc import AsyncIterator
|
||||
from datetime import UTC, datetime
|
||||
from datetime import UTC, datetime, timedelta, timezone
|
||||
from typing import Any
|
||||
from urllib.parse import urlencode
|
||||
|
||||
@@ -184,6 +184,21 @@ class MiFitnessCloudAdapter(DataAdapter):
|
||||
await asyncio.sleep(0.5 * (attempt + 1))
|
||||
raise RuntimeError(f"Mi Fitness request failed: {last_error}")
|
||||
|
||||
|
||||
def _request_timezone(self, region: str | None = None) -> timezone:
|
||||
region_name = self.region if region is None else region
|
||||
if region_name in ("", "cn"):
|
||||
return timezone(timedelta(hours=8))
|
||||
return UTC
|
||||
|
||||
def _date_range_to_timestamps(
|
||||
self, start_date: str, end_date: str, region: str | None = None
|
||||
) -> tuple[int, int]:
|
||||
tz = self._request_timezone(region)
|
||||
start_dt = datetime.fromisoformat(start_date).replace(tzinfo=tz)
|
||||
end_dt = datetime.fromisoformat(end_date + "T23:59:59").replace(tzinfo=tz)
|
||||
return int(start_dt.timestamp()), int(end_dt.timestamp())
|
||||
|
||||
async def _fetch_key(
|
||||
self, key: str, start_date: str, end_date: str, region: str | None = None
|
||||
) -> list[dict]:
|
||||
@@ -193,10 +208,7 @@ class MiFitnessCloudAdapter(DataAdapter):
|
||||
if region_name in ("", "cn")
|
||||
else f"https://{region_name}.hlth.io.mi.com"
|
||||
)
|
||||
start_time = int(datetime.fromisoformat(start_date).replace(tzinfo=UTC).timestamp())
|
||||
end_time = int(
|
||||
datetime.fromisoformat(end_date + "T23:59:59").replace(tzinfo=UTC).timestamp()
|
||||
)
|
||||
start_time, end_time = self._date_range_to_timestamps(start_date, end_date, region_name)
|
||||
next_key = None
|
||||
items: list[dict] = []
|
||||
|
||||
@@ -259,8 +271,9 @@ class MiFitnessCloudAdapter(DataAdapter):
|
||||
|
||||
def _record_datetime(self, item: dict) -> datetime:
|
||||
timestamp = int(item.get("time", 0))
|
||||
zone_offset = int(item.get("zone_offset", 0))
|
||||
return datetime.fromtimestamp(timestamp + zone_offset, tz=UTC).replace(tzinfo=None)
|
||||
zone_offset = int(item.get("zone_offset", 0) or 0)
|
||||
tz = timezone(timedelta(seconds=zone_offset))
|
||||
return datetime.fromtimestamp(timestamp, tz=tz)
|
||||
|
||||
def _parse_value(self, item: dict) -> dict[str, Any]:
|
||||
raw = item.get("value", "{}")
|
||||
@@ -269,7 +282,8 @@ class MiFitnessCloudAdapter(DataAdapter):
|
||||
return json.loads(raw)
|
||||
|
||||
def _timestamp_to_datetime(self, timestamp: Any, zone_offset: int = 0) -> datetime:
|
||||
return datetime.fromtimestamp(int(timestamp) + int(zone_offset), tz=UTC).replace(tzinfo=None)
|
||||
tz = timezone(timedelta(seconds=int(zone_offset or 0)))
|
||||
return datetime.fromtimestamp(int(timestamp), tz=tz)
|
||||
|
||||
async def _fetch_sport_records_by_time(
|
||||
self, start_date: str, end_date: str, region: str | None = None
|
||||
@@ -280,10 +294,7 @@ class MiFitnessCloudAdapter(DataAdapter):
|
||||
if region_name in ("", "cn")
|
||||
else f"https://{region_name}.hlth.io.mi.com"
|
||||
)
|
||||
start_time = int(datetime.fromisoformat(start_date).replace(tzinfo=UTC).timestamp())
|
||||
end_time = int(
|
||||
datetime.fromisoformat(end_date + "T23:59:59").replace(tzinfo=UTC).timestamp()
|
||||
)
|
||||
start_time, end_time = self._date_range_to_timestamps(start_date, end_date, region_name)
|
||||
next_key = None
|
||||
items: list[dict] = []
|
||||
|
||||
|
||||
@@ -457,7 +457,11 @@ class Database:
|
||||
timezone, collected_at, timestamp, bpm, sample_type
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
timezone = excluded.timezone,
|
||||
collected_at = excluded.collected_at,
|
||||
timestamp = excluded.timestamp,
|
||||
bpm = excluded.bpm,
|
||||
sample_type = excluded.sample_type,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
""",
|
||||
(
|
||||
@@ -486,6 +490,9 @@ class Database:
|
||||
timezone, collected_at, timestamp, spo2_pct
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
timezone = excluded.timezone,
|
||||
collected_at = excluded.collected_at,
|
||||
timestamp = excluded.timestamp,
|
||||
spo2_pct = excluded.spo2_pct,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
""",
|
||||
@@ -514,6 +521,9 @@ class Database:
|
||||
timezone, collected_at, timestamp, stress_score, level
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
timezone = excluded.timezone,
|
||||
collected_at = excluded.collected_at,
|
||||
timestamp = excluded.timestamp,
|
||||
stress_score = excluded.stress_score,
|
||||
level = excluded.level,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
@@ -544,6 +554,8 @@ class Database:
|
||||
timezone, collected_at, event_id, start_at, end_at, duration_seconds
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(user_id, event_id) DO UPDATE SET
|
||||
timezone = excluded.timezone,
|
||||
collected_at = excluded.collected_at,
|
||||
start_at = excluded.start_at,
|
||||
end_at = excluded.end_at,
|
||||
duration_seconds = excluded.duration_seconds,
|
||||
@@ -622,7 +634,7 @@ class Database:
|
||||
"""
|
||||
SELECT * FROM sleep_sessions
|
||||
WHERE user_id = ?
|
||||
AND date(start_at) >= ? AND date(start_at) <= ?
|
||||
AND substr(start_at, 1, 10) >= ? AND substr(start_at, 1, 10) <= ?
|
||||
ORDER BY start_at
|
||||
""",
|
||||
(user_id, start_date, end_date),
|
||||
@@ -641,7 +653,7 @@ class Database:
|
||||
"""
|
||||
SELECT * FROM workouts
|
||||
WHERE user_id = ?
|
||||
AND date(start_at) >= ? AND date(start_at) <= ?
|
||||
AND substr(start_at, 1, 10) >= ? AND substr(start_at, 1, 10) <= ?
|
||||
ORDER BY start_at
|
||||
""",
|
||||
(user_id, start_date, end_date),
|
||||
@@ -660,7 +672,7 @@ class Database:
|
||||
"""
|
||||
SELECT * FROM body_measurements
|
||||
WHERE user_id = ?
|
||||
AND date(timestamp) >= ? AND date(timestamp) <= ?
|
||||
AND substr(timestamp, 1, 10) >= ? AND substr(timestamp, 1, 10) <= ?
|
||||
ORDER BY timestamp
|
||||
""",
|
||||
(user_id, start_date, end_date),
|
||||
@@ -678,7 +690,7 @@ class Database:
|
||||
"""
|
||||
SELECT * FROM heart_rate_samples
|
||||
WHERE user_id = ?
|
||||
AND date(timestamp) >= ? AND date(timestamp) <= ?
|
||||
AND substr(timestamp, 1, 10) >= ? AND substr(timestamp, 1, 10) <= ?
|
||||
ORDER BY timestamp
|
||||
""",
|
||||
(user_id, start_date, end_date),
|
||||
@@ -696,7 +708,7 @@ class Database:
|
||||
"""
|
||||
SELECT * FROM spo2_samples
|
||||
WHERE user_id = ?
|
||||
AND date(timestamp) >= ? AND date(timestamp) <= ?
|
||||
AND substr(timestamp, 1, 10) >= ? AND substr(timestamp, 1, 10) <= ?
|
||||
ORDER BY timestamp
|
||||
""",
|
||||
(user_id, start_date, end_date),
|
||||
@@ -714,7 +726,7 @@ class Database:
|
||||
"""
|
||||
SELECT * FROM stress_samples
|
||||
WHERE user_id = ?
|
||||
AND date(timestamp) >= ? AND date(timestamp) <= ?
|
||||
AND substr(timestamp, 1, 10) >= ? AND substr(timestamp, 1, 10) <= ?
|
||||
ORDER BY timestamp
|
||||
""",
|
||||
(user_id, start_date, end_date),
|
||||
@@ -732,7 +744,7 @@ class Database:
|
||||
"""
|
||||
SELECT * FROM abnormal_heart_beat_events
|
||||
WHERE user_id = ?
|
||||
AND date(start_at) >= ? AND date(start_at) <= ?
|
||||
AND substr(start_at, 1, 10) >= ? AND substr(start_at, 1, 10) <= ?
|
||||
ORDER BY start_at
|
||||
""",
|
||||
(user_id, start_date, end_date),
|
||||
@@ -768,9 +780,9 @@ class Database:
|
||||
row = conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
MIN(date(start_at)) as first_date,
|
||||
MAX(date(start_at)) as last_date,
|
||||
COUNT(DISTINCT date(start_at)) as days_with_data
|
||||
MIN(substr(start_at, 1, 10)) as first_date,
|
||||
MAX(substr(start_at, 1, 10)) as last_date,
|
||||
COUNT(DISTINCT substr(start_at, 1, 10)) as days_with_data
|
||||
FROM sleep_sessions
|
||||
WHERE user_id = ?
|
||||
""",
|
||||
@@ -788,9 +800,9 @@ class Database:
|
||||
row = conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
MIN(date(start_at)) as first_date,
|
||||
MAX(date(start_at)) as last_date,
|
||||
COUNT(DISTINCT date(start_at)) as days_with_data
|
||||
MIN(substr(start_at, 1, 10)) as first_date,
|
||||
MAX(substr(start_at, 1, 10)) as last_date,
|
||||
COUNT(DISTINCT substr(start_at, 1, 10)) as days_with_data
|
||||
FROM workouts
|
||||
WHERE user_id = ?
|
||||
""",
|
||||
@@ -808,9 +820,9 @@ class Database:
|
||||
row = conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
MIN(date(timestamp)) as first_date,
|
||||
MAX(date(timestamp)) as last_date,
|
||||
COUNT(DISTINCT date(timestamp)) as days_with_data
|
||||
MIN(substr(timestamp, 1, 10)) as first_date,
|
||||
MAX(substr(timestamp, 1, 10)) as last_date,
|
||||
COUNT(DISTINCT substr(timestamp, 1, 10)) as days_with_data
|
||||
FROM body_measurements
|
||||
WHERE user_id = ?
|
||||
""",
|
||||
@@ -827,9 +839,9 @@ class Database:
|
||||
row = conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
MIN(date(timestamp)) as first_date,
|
||||
MAX(date(timestamp)) as last_date,
|
||||
COUNT(DISTINCT date(timestamp)) as days_with_data
|
||||
MIN(substr(timestamp, 1, 10)) as first_date,
|
||||
MAX(substr(timestamp, 1, 10)) as last_date,
|
||||
COUNT(DISTINCT substr(timestamp, 1, 10)) as days_with_data
|
||||
FROM heart_rate_samples
|
||||
WHERE user_id = ?
|
||||
""",
|
||||
|
||||
Reference in new issue
Block a user