Timestamps

All Vital data timestamps are ISO 8601 formatted as follows:

ProvidersTime BasisPattern
Freestyle Libre [1]Floating Time [2]YYYY-mm-ddTHH:mm:ss+00:00
The +00:00 TZ specifier should be ignored [3].
Everyone elseUTCYYYY-mm-ddTHH:mm:ss+00:00
Always specified as +00:00 (UTC).

[1] Some older teams may see floating time data (Freestyle Libre) without the +00:00 TZ specifier, as part of an earlier iteration of the feature. Contact Vital support if you wish to disable this behaviour, or if you intend to adopt the Vital backend SDKs.

[2] Floating time is not affixed to any time zone. This is not the same as time relative to a local time zone, i.e., a known UTC offset or geographical location.

[3] Vital sends timestamps in floating time with +00:00 for OpenAPI 3.x interoperability. OAS 3 requires all timestamps to be RFC 3339, which in turn requires TZ specifier to be mandatory.

When processing data from Freestyle Libre, you should reinterpret literally the date and time components as local date-time in the desired time zone. Do not convert from UTC/Zulu.

Time Zones

Vital formats time zones in data as a nullable integer offset to UTC:

  • A positive offset indicates east of UTC.
  • A negative offset indicates west of UTC.
  • null indicates the time zone information is absent.

Each provider has their own affinity of time zone information:

AffinityTime BasisTime Zone
UTCThe data comes with time zone information.
User Fallback, or UTCUTCWe assume the data were captured in the User Fallback Time Zone. We fallback to UTC if the former is not set.
User Fallback, or AbsentUTCWe assume the data were captured in the User Fallback Time Zone. Mark as no time zone (null) if the former is not set.
Inferred, or AbsentUTCWe infer the time zone from the data. Mark as no time zone (null) if the inferrence fails.
AbsentUTCWe do not know the exact time zone the recording took place in. Mark as no time zone (null).
Floating TimeFloating TimeWe do not know the exact time zone the recording took place in. Mark as no time zone (null).

Cloud-based Providers

ProviderActivity Summary (Daily)Session Summary (e.g. Sleep)Timeseries Sample
Freestyle Libre freestyle_libreN/AN/AFloating Time
Fitbit fitbit
Garmin garmin
Google Fit google_fitUser Fallback, or UTCUser Fallback, or AbsentAbsent
Oura oura
Peloton pelotonN/AN/A
Renpho renphoN/AAbsent
Strava stravaN/A
Wahoo wahooN/AAbsentN/A
Whoop whoop_v2N/A
Zwift zwiftN/AUser Fallback, or AbsentN/A
Withings withings
iHealth ihealthN/AAbsent
8Sleep eight_sleepN/A
Hammerhead hammerheadN/AInferred, or AbsentInferred, or Absent
Dexcom dexcom_v3N/AN/A
Polar polar
Kardia kardiaN/AN/A
Omron omronN/A

SDK-based Providers

On-device data often do not capture the time zone at recording time. Vital SDK uses the device’s current time zone as the fallback of closest approximation.

ProviderActivity Summary (Daily)Session SummaryTimeseries Samples
Apple HealthKit apple_health_kit
Android Health Connect health_connect
Omron omron_bleN/AN/A
Contour contour_bleN/AN/A
Accu-Chek accuchek_bleN/AN/A
Freestyle Libre BLE freestyle_libre_bleN/AN/A

Examples

Data point with time zone offset

The data point was recorded on July 7, 2023 at 1:00 PM in UTC-07:00.

{
  "source": {
    "provider": "apple_health_kit",
  },
  "data": [
    {
      "timestamp": "2023-07-07T20:00:00+00:00",
      "timezone_offset": -25200
    }
  ]
}

Data point with no time zone offset (null)

The data point was timestamped to Aug 13, 2023 at 8:12 AM in UTC+00:00 (Zulu). We do not know the exact time zone the recording took place in.

{
  "source": {
    "provider": "apple_health_kit",
  },
  "data": [
    {
      "timestamp": "2023-08-13T08:12:00+00:00",
      "timezone_offset": null
    }
  ]
}

Data point in floating time (Freestyle Libre)

This Freestyle Libre data point was recorded on Sep 27, 2023 at 7:48 AM in floating time (whichever time zone the user was in). We do not know the exact time zone the recording took place in.

You can display the date and time components literally to the user, e.g., 2023/09/27 07:48 AM, as they are relative to their perception of local time.

If you need to convert it to UTC for persistence, you need to pick a time zone based on your understanding of the user. Then you should reinterpret the date and time components literally in said time zone.

For example, we knew that this example user is based in America/New_York. So we would interpret this data point to be in 2023/09/27 07:48 AM ET. We then finally convert this to UTC, resulting in 2023/09/27 11:48 AM UTC.

{
  "source": {
    "provider": "freestyle_libre",
  },
  "data": [
    {
      "timestamp": "2023-09-27T07:48:00+00:00",
      "timezone_offset": null
    }
  ]
}

User Fallback Time Zone

Some providers neither expose nor even capture time zone information at source. So Vital can only request data and interpret them strictly in UTC.

If you prefer the data to be contextualize to the geographical location of a user, a Fallback Time Zone (denoted by an IANA tz database identifier) can be specified on a per-user basis. Once specified, Vital would use the time zone to pull data and interpret timestamps from any time zone unware providers from that point onwards.

You can specify the Fallback Time Zone when:

You will also get information about the source (by slug) and the last updated time of the Fallback Time Zone when getting an existing user. Fallback Time Zone manually supplied via the REST API would always have a source slug of manual.

Example
{
  "user_id": "409d9870-21fb-443a-8daa-c5222659f40e",
  "team_id": "3aac677c-557f-40b7-9251-0315c1f48e77",
  "client_user_id": "d734e32e-dd43-4b77-ab56-692524279531",
  /** snipped **/
  "fallback_time_zone": {
    "id": "Europe/London",
    "source_slug": "manual",
    "updated_at": "2022-09-11T13:45:56+00:00"
  }
}