Javascript SDK with convertDateTimesToDates=true does not convert localDateTime

Hello

Javascript SDK with convertDateTimesToDates=true does not convert localDateTime: when decoding dates to actual dates:

https://github.com/garmin/fit-javascript-sdk/blob/595389e1006460b2de706a2a254694b9ac9972bf/src/decoder.js#L633

The SDK does not take type === "localDateTime" into account.

This results in difficulties to compute the TZ offset as the local time is using a FIT-epoch date when the timestamp was converted to a JS Date

Not a big fix. Any PR welcome?

Best

Jan

  • This is by design. The time zone offset for an activity file is calculated from the delta of the timestamp and local_timestamp in the activity message. Otherwise “local time” would be based on the time zone of the system decoding the file and not the time zone of the activity. Historically the activity message is the last message in the file, so you don’t know what the time zone offset is until all messages are read from the file. There is a section in this recipe on “Converting Timestamps to Local Time” that covers some of this.

    https://developer.garmin.com/fit/cookbook/decoding-activity-files/

    If there is a need to convert local time stamps to JavaScript Date objects, that can be done using a message listener. That would look something like this.

    import { Decoder, Stream, Profile, Utils } from "@garmin-fit/sdk";

    const
    onMesg = (mesgNum, mesg) => {

    if ("localTimeStamp" in mesg) {

    mesg.localTimestamp = Utils.convertDateTimeToDate(mesg.localTimestamp);

    }

    // Or...
      if (mesgNum === Profile.MesgNum.ACTIVITY) {
         tzOffset = (mesg.localTimestamp ?? mesg.timestamp) - mesg.timestamp;
     }

    }

    const { messages, errors } = decoder.read({

    mesgListener: onMesg,

    });

    In my own projects that use the JavaScript SDK, I always set convertDateTimesToDates=false. The reason being is that there are a lot of timestamps in a file, but only a few that are ever shown to the user in local time so I just convert the ones that are shown to the user. On a chart there could be10k data points but only 10 x-axis labels. So I will convert the FIT timestamps to JavaScript Date objects in the axis label callbacks. This saves some processing time during decoding, saves memory w/o all of the Date objects, and makes other calcs faster and easier since the timestamps are numbers and not Dates.

  • Hi Ben

    Thanks again for that answer. Makes a lot of sense! After I posted the question, I ended up with the same conclusion as you regarding the performance aspect.

    I just thought that I wished a flag "convertToUnixEpoch" that would take care of shifting all dates by the FIT_EPOCH and convert to millis so that creating the date is less error prone (whether JS Date, MomentJs or Luxon, all take a unix timestamp in millis). The range of the number type in JS does not make it subject to Y2038 bug.

  • Small afterthought: I don't think we have a way to easily implement that conversion to unix epoch millis ourselves, do we?

    I guess the mesgListener is of no help here because the fields metadata were already discarded here, and there is no fieldListener that would mimic the mesgListener for all fields.