14 Feb 21 16:47, you wrote to me:
But maybe the correct code should be:
         if (*msg->__ftsc_date)
         {
             ftsdate = msg->__ftsc_date;
         }
         else
         {
             scombo = (SCOMBO *)(&(msg->date_written));
             scombo = TmDate_to_DosDate(s_time, scombo);
             ftsdate = (unsigned char *)sc_time(scombo, (char
*)(msg->__ftsc_date)); }
Mhh, a JAM message base doesn't have an __ftsc_date field, I don't understand this piece of the code.
Yeah, disregard that, I wrote it in a hurry.
I've also never used JAM much so don't recall much about the file format, but see below.
        dosdate->msg_st.time.mm = tmdate->tm_min;
        dosdate->msg_st.time.ss = tmdate->tm_sec >> 1;
                                          ^^^^^^^^^^^^
    }
    return dosdate;
}
AFAIK the JAM format doesn't use DOS Time at all. It seems to be an unnecessary lossy conversion.
Scott Dudley's MSGAPI uses lossy timestamps internally for XMSG->date_written and XMSG->date_arrived and that's folded into the SMAPI fork because nobody's ever thought to change it. See _stamp in huskylib/cvtdate.h.
(The _stamp struct is in Huskylib now, but it was originally self-contained in SMAPI, which predates the Husky project.)
Scott's idea of using his lossy timestamps to recreate XMSG->__ftsc_date is nonsense and as you know only has a 50/50 chance of working accurately.
Now, the Squish format stupidly uses those lossy timestamps but there's no reason the whole API has to. Conceivably that could be fixed with a bit of work so as not to corrupt Squish bases.
In the mean time JAM's msgh->Hdr.DateWritten is a 32-bit unsigned integer. (Fortunately being unsigned it will wrap around in 2106, not in 2038.)
The JAM spec says:
"An ulong representing the number of seconds since midnight, January 1, 1970."
Presumably that's 1970-01-01 00:00 UTC, not local time.
When writing messages, JamWriteMsg() calls ConvertXmsgToJamHdr() (which is not used by JamReadMsg), which does this:
    jamhdr->DateWritten = mktime(ptm) + gettz();
One problem here is that ptm is assigned the return value of DosDate_to_TmDate(), which I suspect is lossy. I don't know why the code does that.
That value is then fed into mktime() to return the number of seconds since 1970-01-01, then a timezone offset is added with gettz().
But why is gettz() called every time JamWriteMsg() is called? Wouldn't that mean HPT adds the local timezone to the DateWritten field every time it tosses a message to a JAM base? That's a bug, isn't it? Unless I'm reading the code wrong.
I mean, JamReadMsg() could convert msgh->Hdr.DateWritten to FTSC date format then write that to msg->__ftsc_date, but will the __ftsc_date of rescanned messages have the same timestamp they originated with, or will they be offset by local time?
If the latter, it's not just a matter of reversing things by subtracting the offset of local time, because the local time zone can change due to daylight savings.
Though I just noticed gettz() seems to unexpectedly disable DST when it calculates the time zone offset! So maybe you /could/ subtract the offset and the rescanned timestamps would be accurate... unless you moved into a different time zone.
api_jam.c also hints at supporting the TZUTC kludge, but it does nothing to calculate dates with it. It just stores it as a JAM subfield because the spec says it can.
The ftsdate variable in JamReadMsg() doesn't actually seem to be used. Abandoned code, I guess.
--- GoldED+/BSD 1.1.5-b20180707
 * Origin: Blizzard of Ozz, Melbourne, Victoria, Australia (3:633/267)