Fit file: record timestamps

Former Member
Former Member

Is it possible to store records with a milliseconds timestamp? According to the documentation it is stored at seconds.

  • I thought, as stated in the first message, that FIT only record timestamp with second resolution (and not millisecond) so how is it done?

  • I think what "Ben FIT" was referring to was the specific message type "Record" (global id 20), which indeed has no millisecond timestamp. However, some message types do have a fractional/millisecond timestamp, such as the message type "gps_metadata" (global id 160) when logged by, for example, a VIRB Ultra 30 (note that other devices that log "gps_metadata" may not have all the fields the VIRB logs).

    EDIT: the VIRB Ultra 30 logs GPS at 1Hz in Record/20 and at 10Hz in gps_metadata/160. Haven't checked whether the 1Hz coordinate in Record/20 is an averge of previous gps_metadata messages or not.

    Here's an example of "Record"/20 from a VIRB Ultra 30 FIT file:

    [194] Global ID: 20 | Message type: record | Header: 12/0b00001100
        id: 253 timestamp             : UINT32([195]) 
        id:   0 position_lat          : SINT32([664616236]) 
        id:   1 position_long         : SINT32([157484473]) 
        id:   5 distance              : UINT32([2589]) 
        id:  73 enhanced_speed        : UINT32([513]) 
        id:  78 enhanced_altitude     : UINT32([2859])

    Here's an example of "gps_metadata"/160 from a VIRB Ultra 30 FIT file, note the "timestamp_ms" field which logs the millisecond part of the timestamp:

    [581] Global ID: 160 | Message type: gps_metadata | Header: 11/0b00001011
        id: 253 timestamp             : UINT32([195]) 
        id:   1 position_lat          : SINT32([664616318]) 
        id:   2 position_long         : SINT32([157484457]) 
        id:   3 enhanced_altitude     : UINT32([2946]) 
        id:   4 enhanced_speed        : UINT32([755]) 
        id:   6 utc_timestamp         : UINT32([864990537]) 
        id:   0 timestamp_ms          : UINT16([989]) 
        id:   5 heading               : UINT16([35439]) 
        id:   7 velocity              : SINT16([-7, 75, 2]) 
        id:   8 UNDEFINED_FIELD_8     : UINT16([9]) 
        id:   9 UNDEFINED_FIELD_9     : UINT16([11]) 
        id:  10 UNDEFINED_FIELD_10    : UINT16([14]) 
        id:  11 UNDEFINED_FIELD_11    : UINT16([359]) 
        id:  12 UNDEFINED_FIELD_12    : UINT16([217])

  • Oh ok great!

    Any idea how it looks like once changed to GPX format? 

  • It depends on how you write the GPX file. There is (as far as I know) no official conversion process or tool (?). This means that what in the FIT-data goes where in the GPX file is arbitrary and up to the developer. But at least GPX timestamps conform to ISO8601 and allow for millisecond granularity (here's the schema for "waypoint": https://www.topografix.com/GPX/1/1/#type_wptType click "?" for "time").

    GPS Babel does some conversions, but previously seemed to use "Record"/20, meaning 1Hz only, which is understandable since that can probably be found in all devices that log to FIT.

    I have made a custom tool to convert VIRB gps_metadata messages to KML. If you have a VIRB Ultra 30 FIT-file, the simplest command would be (downsampling possible):

    geoelan check -f VIRBFITFILE.fit --kml # 10Hz KML
    geoelan check -f VIRBFITFILE.fit --kml --downsample 10 # 1Hz KML

    The generated KML-file includes the millisecond part of the timestamp and validates. I don't know of a more generally available tool that does this.