difftime and libc_difftime passed their arguments to the host CRT.
UCRT's _difftime64 returns 0 and sets errno to EINVAL when either
argument is negative (common_difftime in ucrt/time/difftime.cpp), so
on Windows difftime(0, -1) returned 0 instead of 1 and every
difference involving a time before 1970 was 0. C17 7.27.2.2 defines
the result as time1 - time0, and FreeBSD 11's difftime
(contrib/tzcode/stdtime/difftime.c) and glibc on the Linux build
compute it for any arguments.
Subtract the smaller time from the larger as uint64_t, which cannot
overflow, convert the difference to double and negate it when time1
is the smaller one, as FreeBSD and glibc's fallback path do. The
result is time1 - time0 rounded once to double on both hosts.
difftime now forwards to libc_difftime like the other aliases in the
file.
gmtime, localtime, mktime, strftime and asctime took and returned the
host std::tm. The guest's FreeBSD tm has tm_gmtoff and tm_zone after the
nine calendar fields, so on Windows, where std::tm is 36 bytes, a title
reading those fields read past the thread-local result, and gmtime_s left
them unwritten. Windows gmtime_s also accepts only 1969-12-31 12:00 to
3001-01-19 21:59 UTC, where the guest libc converts any time.
Convert through a GuestTm with the guest layout on both hosts. Compute
the UTC fields from the day count, so every time whose year fits an int
converts, and on Windows take the local offset and zone name from the
CRT. gmtime reports the zone as UTC like the guest libc. localtime and
mktime keep the CRT's range on Windows; recorded in TechnicalDebt.
Co-Authored-By: Claude Fable 5.1 <[email protected]>