ADD windows support for USE_SYSTEM_TZ_DB
Windows support for USE_SYSTEM_TZ_DB
These changes add support for the USE_SYSTEM_TZ_DB option on windows. These changes increase the speed of timezone conversion operations by many orders of magnitude (see benchmarks below).
The majority of the changes are in the init_tzdb function. There I added support for the windows file API to load the timezone database off of disk.
This Addresses...
- https://github.com/HowardHinnant/date/issues/541
- https://github.com/HowardHinnant/date/issues/453
Configuration
Along with these changes, I've added the option to specify the location of the zoneinfo TZDIR by environment variable. To my knowledge, there is no one standard place for the system tz database to live on windows. This means that for those to choose to use USE_SYSTEM_TZ_DB on windows will need to compile their own tz database from iana and specify its location via the TZDIR environment variable. It is my belief that this trade off is well worth it. The performance benefits speak for themselves.
Benchmarks
To test the benefits of the changes I ran this basic benchmark that times many timezone conversions.
see this repo for full implementation
TEST( date, bench1 )
{
using namespace std::chrono;
using namespace date;
int n = 10000;
auto sw = StopWatch();
// lookup for every call in tz db,,,
{
auto tpUTC = std::chrono::system_clock::now();
auto const* tz = date::locate_zone( "America/New_York" ); // locate the timezone once
fmt::print( "locate_zone: time used {} us\n", sw.elapsedUs() );
sw.restart();
for( int i = 0; i != n; ++i )
{
auto const zt = make_zoned( tz, tpUTC );
auto const tp = zt.get_local_time(); // expensive call
auto const dp = floor<days>( tp );
auto const ymd = year_month_day( dp );
}
}
fmt::print( "lookup: every call: time used {} us\n", sw.elapsedUs() );
sw.restart();
// should be way faster
{
auto tpUTC = std::chrono::system_clock::now();
for( int i = 0; i != n; ++i )
{
const std::string zone = "America/New_York";
auto const zt = make_zoned( zone, tpUTC ); // locate the timezone every time
auto const tp = zt.get_local_time();
auto const dp = floor<days>( tp );
auto const ymd = year_month_day( dp );
}
}
fmt::print( "lookup: once : time used {} us\n", sw.elapsedUs() );
}
Using the regular (non system) timezone database on windows, I get these results:
USE_SYSTEM_TZ_DB=OFF
[ RUN ] date.bench1
locate_zone: time used 2125059 us
lookup: every call: time used 2041528 us
lookup: once : time used 2066843 us
[ OK ] date.bench1 (6234 ms)
With these changes, and a compiled iana database:
USE_SYSTEM_TZ_DB=ON
[ RUN ] date.bench1
locate_zone: time used 43170 us
lookup: every call: time used 52907 us
lookup: once : time used 803878 us
[ OK ] date.bench1 (900 ms)
Overall these changes allow for about ~7x faster timezone conversions on Windows.
I'm interested in these changes from a packaging perspective - this is pretty stale though, is there likely to be any movement on merging this in?
For Windows platforms I strongly encourage people to migrate to C++20 <chrono>.
According to Microsoft documentation, time zone support is only available on
- Windows 10 version 1903/19H1 or later
- Windows Server 2022 or later
If my project is compiled with C++20, i will not be able to use it on Windows Server 2019, am i right ? In that case, i still need to use your library ?
@wabscale can you comment on the utility of the TZDATA_DIR vs TZDIR environment variables? why are these not the same in this PR?
@wabscale can you comment on the utility of the
TZDATA_DIRvsTZDIRenvironment variables? why are these not the same in this PR?
That appears to be a mistake on my part. If this ever makes it into this library, this PR will need to be rewritten anyway. My original repo is many commits behind because of how long this issue has been open.