On 23/12/2023 02:41, Jeffrey Walton wrote:
I've found lack of per-thread timezones and libc's inability to
convert time between timezones a bigger problem than other issues,
like explicitly setting a timezone for a process.

From my point of view the TZ environment variable makes timezone conversion a rather expensive operation. Some libc limitations are highlighted in
https://data.iana.org/time-zones/theory.html#POSIX

The use case is, an appointment needs to be added to a database with
UTC time, but the sender of the appointment uses localtime+timezone
offset, like 1:00 PM PST or 1:00 PM EST. Trying to convert the
localtime+timezone time to UTC (or other timezone) on a server in a
thread is a real nightmare. Also see
<https://sourceware.org/pipermail/libc-help/2021-January/005652.html>.

From that message:
  * given: '15 Jan 2021 01:24:55 -0800 (PST)

Time zone offset is given, so the timestamp can be unambiguously converted to UTC or seconds since epoch.

If the DB is Postgres then I would delegate timezone-related computations to it.

Posting code that can not be compiled may hide real issue.

A couple of issues that may lead to undefined behavior:

(info "(libc) Low-Level Time String Parsing")
https://www.gnu.org/software/libc/manual/html_node/Low_002dLevel-Time-String-Parsing.html#index-strptime
   • Before calling the ‘strptime’ function for a new input string, you
     should prepare the TM structure you pass.  Normally this will mean
     initializing all values to zero.  Alternatively, you can set all
     fields to values like ‘INT_MAX’, allowing you to determine which
     elements were set by the function call.  Zero does not work here
     since it is a valid value for many of the fields.

Before calling mktime set tm_isdst to negative value if you do not know if DST is effective that moment.

However being aware of tm_gmtoff GNU extension, I was not expected the following:

(info "(libc) Broken-down Time")
https://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html#index-mktime
     The ‘mktime’ function ignores the specified contents of the
     ‘tm_wday’, ‘tm_yday’, ‘tm_gmtoff’, and ‘tm_zone’ members of the
     broken-down time structure.  It uses the values of the other
     components to determine the calendar time; it’s permissible for
     these components to have unnormalized values outside their normal
     ranges.  The last thing that ‘mktime’ does is adjust the components
     of the BROKENTIME structure, including the members that were
     initially ignored.

So before calling mktime you need to set a timezone having offset of -0800. I have not figured out if the following approach may give incorrect results for some corner cases:

- save tm_gmtoff from strptime results
- set UTC timezone
- call mktime
- adjust result by saved tm_gmtoff

Besides performance penalty due to tzset() I would not call it "nightmare".

Beware with real timezones having DST or other time transitions. GNU libc implementation of mktime may give different results for the same passed argument depending of argument used for previous call.

I would consider using some other library instead of libc:
- std::chrono (I have heard of other C++ libraries created before chrono was added to the standard)
- Qt
- timelib C library from PHP

P.S.
https://stackoverflow.com/questions/11004273/what-is-stdpromise
std::broken_promise is the best named identifier in the standard
library. And there is no std::atomic_future.
 – Cubbi Jun 12, 2012 at 22:26
struct tm is referred to as "Broken-down" time

Reply via email to