HowardHinnant / date

A date and time library based on the C++11/14/17 <chrono> header
Other
3.14k stars 677 forks source link

TZ DB Code Path for Embedded Use - Request for Comment #736

Closed Justin-Hoffman closed 2 years ago

Justin-Hoffman commented 2 years ago

There are a number of code paths for configuring the source of the IANA timezone database (system provided, manually specified database path, auto-download on first access, etc.). None of these solutions are well suited for embedded applications for which a file system and network connection may not exist.

I propose that an additional compile-time configurable code path be provided that allows for embedding the database into the library binary itself so that the tz db can be used on systems which lack a file system. This could be implemented by requiring the user to provide a source file which contains wstringbufs where each wstringbuf is initialized with the contents of each of the required files provided by IANA. In addition to this, a code block is added to init_tzdb() to read from these wstringbufs instead of from files. The code block would be turned on/off via preprocessor defines in the same fashion that other platform and code path specific blocks are.

If a pull request providing the above functionality were provided (it doesn't currently exist), would you be interested in reviewing and possibly accepting?

In addition to the above proposed functionality for an embedded database code path, some other conveniences could be added, for example:

For some build systems, a build step could be added to fetch the database from IANA and generate the mentioned source file with populated wstringbufs (turning the run-time database download into a build-time database download + code generation). This is not strictly necessary.

One might also prefer to allocate large enough buffers to allow for runtime overwrite of these buffers without recompiling the binary (for example in an embedded case where a file system is not available but for which a network connection is available).

HowardHinnant commented 2 years ago

Thanks for the thoughts.

This idea was floated years ago, and I declined it. One of the problems is that it presumes a version of the database at compile-time. Such an executable is bound to go at least a little obsolete within a couple of months, and the scale of the divergence between the executable and the current database grows significantly over the course of a couple of years.

I understand that there may be use cases where such divergence is acceptable. However I believe it is too much complication for a goal that this library was never meant to support. The main goal of this library was to get field experience for standardization. Goal accomplished. This is now in C++20.

That still leaves you out in the cold, which of course I'm not happy with. One possibility is for you to use a custom time zone. The zoned_time class can accept user-written time zones, and if you have C++17, the syntax is really nice. If you don't, type-aliases can make the syntax nice.

With a custom time zone you could embed whatever time zone information you want in your app and use it as you describe.

Search for "Custom time zone" under https://howardhinnant.github.io/date/tz.html#Examples for the simplest example of what a custom time zone looks like. For a more complete example, see https://github.com/HowardHinnant/date/blob/master/include/date/ptz.h which models POSIX timezones. An example use case of the latter (in C++17) looks like:

#include "date/ptz.h"
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;

    auto now = system_clock::now();
    auto tzp = Posix::time_zone{"EST5EDT,M3.2.0,M11.1.0"};
    cout << zoned_time{tzp, now} << '\n';
}

That just output:

2022-05-18 15:22:45.855639 EDT

for me. And ptz.h is a header-only lib. No need to compile tz.cpp.

Justin-Hoffman commented 2 years ago

Thanks Howard and understood. I'll explore dropping the tz.cpp use and providing my own time zones.

I had originally hoped to just use the C++20 standard library but I'm finding that at least the gnu standard library doesn't provide a complete implementation for some clocks that were of importance to me (utc_clock, gps_clock) (at least at the latest GCC 12.1): https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/std/chrono;hb=HEAD#l74 I had to come back here for a complete implementation. Perhaps they punted on this to avoid dealing with the stale database problem, and perhaps this is another point in favor of just re-implementing a simple subset myself until support matures.

HowardHinnant commented 2 years ago

The custom time zone support is in C++20, so your code should port when gcc gets up to speed.