-
Notifications
You must be signed in to change notification settings - Fork 170
Description
Region and Brand of car
HY - EU
Version of the API
4.3.11
Describe the behavior
After fixing Hyundai-Kia-Connect/kia_uvo#1378 i got reliable updates for my car every 30 minutes.
However, one thing surprised me is that the "Last Updated At" is always one hour off.
So first I thought it has something to to with the timestamp from the the Hyundai API, but after looking at the code I realize that it doesn't use it and the value is constructed in my case from "Date" and "Offset".
So I tried to understand why this happens.
So my plausibility check is simple, my wife arrive at work every morning nearly the same time around 6:10am UTC+1 and the values update no later than half an hour later and i got the following values from the API:
"resMsg": {
"lastUpdateTime": "1768453801649",
"state": {
"Vehicle": {
"Date": "20260115051000.000",
"Offset": "1"
}
}
}
}
but HA shows:

which is 1 hour earlier (and so half an our earlier than she depart ;)).
(I know that's not the same day, but i guess you got what I mean)
So I try understand that and "hack" the following python stuff just to make it clear at least to myself:
#!/usr/sbin/python
import datetime
import json
import re
# stipped data from HY API
state = {
"resMsg": {
"lastUpdateTime": "1768453801649",
"state": {
"Vehicle": {
"Date": "20260115051000.000",
"Offset": "1"
}
}
}
}
vehicle = { }
###
# source: https://github.com/Hyundai-Kia-Connect/hyundai_kia_connect_api/blob/84bd2276e24ec97bd672d864c423d99808cb53fb/hyundai_kia_connect_api/utils.py#L56
###
def parse_datetime(value, timezone) -> datetime.datetime:
if value is None:
return datetime.datetime(2000, 1, 1, tzinfo=timezone)
# Try parsing the new format: Tue, 24 Jun 2025 16:18:10 GMT
try:
dt_object = datetime.datetime.strptime(value, "%a, %d %b %Y %H:%M:%S GMT")
if timezone:
# First, make it aware of UTC since 'GMT' implies UTC
utc_dt = dt_object.replace(tzinfo=datetime.timezone.utc)
# Then convert to the target timezone
return utc_dt.astimezone(timezone)
else:
return dt_object
except ValueError:
# If the new format parsing fails, try the old format
value = (
value.replace("-", "").replace("T", "").replace(":", "").replace("Z", "")
)
m = re.match(r"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})", value)
if m:
return datetime.datetime(
year=int(m.group(1)),
month=int(m.group(2)),
day=int(m.group(3)),
hour=int(m.group(4)),
minute=int(m.group(5)),
second=int(m.group(6)),
tzinfo=timezone,
)
else:
raise ValueError(f"Unable to parse datetime value: {value}")
###
# source: https://github.com/Hyundai-Kia-Connect/hyundai_kia_connect_api/blob/84bd2276e24ec97bd672d864c423d99808cb53fb/hyundai_kia_connect_api/ApiImplType1.py#L236
###
offset = float(state["resMsg"]["state"]["Vehicle"]["Offset"])
hours = int(offset)
minutes = int((offset - hours) * 60)
vehicle["datetime_from_timestamp"] = datetime.datetime.fromtimestamp(int(state["resMsg"]["lastUpdateTime"])/1000, datetime.timezone.utc)
vehicle["timezone"] = (datetime.timezone(datetime.timedelta(hours=hours, minutes=minutes)))
vehicle["last_updated_at"] = (parse_datetime(state["resMsg"]["state"]["Vehicle"]["Date"], vehicle["timezone"]))
print("source data:\n", json.dumps(state, indent=4), "\n")
print("API-Timestamp:", state["resMsg"]["lastUpdateTime"], " -> UTC-DateTime:", vehicle["datetime_from_timestamp"])
print("last_updated_at: ", vehicle["last_updated_at"])
This prints the following:
~ tmp/poc.py
source data:
{
"resMsg": {
"lastUpdateTime": "1768453801649",
"state": {
"Vehicle": {
"Date": "20260115051000.000",
"Offset": "1"
}
}
}
}
API-Timestamp: 1768453801649 -> UTC-DateTime: 2026-01-15 05:10:01.649000+00:00
last_updated_at: 2026-01-15 05:10:00+01:00
So the python API assumes the DateTime is in the calculated offset timezone and after "handover" to HA, it is transformed to UTC which it is already and so the values are -1h.
So my assumption is, that the Vehicle Date is always in UTC and with the Offset the User(?) / Car(?) timezone could be calculated.
So maybe someone in another timezone than Europe/Berlin could verify my assumption?
Or did I understand something wrong?