You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit introduces a new implementation of the TimeZoneIf interface
that is compatible with Windows Time APIs.
Background:
Here's a quick comparison of how time zone libraries are implemented on
modern Windows:
* <chrono> in Microsoft STL
-> Uses system "icu.dll" [1] if available [2].
* System.TimeZoneInfo in .NET
-> Uses Windows Registry as the source of time zone information.
* CCTZ
-> Uses zoneinfo if found in TZDIR or ZoneInfoSourceFactory.
This commit brings what .NET does to CCTZ. The major advantages of using
Windows Registry instead of "icu.dll" are:
* It gives the full consistency with the Windows Time APIs.
* The data has proven to be updated via Windows Update in a good
cadence [3]. For instance, tzdb 2022b is still used in "icu.dll"
shipped with Windows 11 24H2.
Implementation Note:
Windows uses per-year time zone information as follows [4]:
struct REG_TZI_FORMAT {
// Base offset in minutes, where UTC == local time + Bias.
LONG Bias;
// Additional offset in minutes applied to standard time.
LONG StandardBias;
// Additional offset in minutes applied to DST.
LONG DaylightBias;
// Localtime (in the previous offset) when the standard time begins.
SYSTEMTIME StandardDate;
// Localtime (in the previous offset) when the DST begins.
SYSTEMTIME DaylightDate;
};
For each time zone ID, one default REG_TZI_FORMAT entry and optional
year-keyed REG_TZI_FORMAT entries are stored under the following
registry keys:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\<zone_id>
Years that are not explicitly covered by a year-keyed entry are governed
by the default entry or the earliest year-keyed entry, respectively.
SYSTEMTIME is defined as follows:
struct SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
};
There are special rules of SYSTEMTIME used in REG_TZI_FORMAT [4]:
* If wMonth is zero, the transition does not occur.
* If wYear is not zero, the transition date is absolute.
* If wYear is zero and wMonth is not zero, the transition rule is
recurring every year based on wDayOfWeek. wDay indicates the
occurrence of the day of the week within the month. wDay == 5 means
the final occurrence during the month.
* All fields are in the local time in the previous offset rather than
the new offset.
* (wHour, wMinute, wSecond, wMilliseconds) == (23, 59, 59, 999) is a
special case that indicates the transition occurs at the end of the
day (i.e., 00:00:00.000 of the next day) [5].
With above, we should be able to implement the TimeZoneIf interface.
Note that only the data loading steps from the Windows Registry need to
be Windows-specific. The rest of the implementation is designed to be
platform-independent in case we want to perform further testing and code
analysis as needed. To run the basic tests, run the following command.
bazelisk test //:time_zone_win_test
How to build:
To actually use it as the fallback mechanism,
CCTZ_USE_WIN_REGISTRY_FALLBACK
macro needs to be defined when building cctz on Windows.
bazelisk run :time_tool \
--cxxopt=/DCCTZ_USE_WIN_REGISTRY_FALLBACK
bazelisk test //:time_zone_lookup_test \
--cxxopt=/DCCTZ_USE_WIN_REGISTRY_FALLBACK
[1]: https://learn.microsoft.com/en-us/windows/win32/intl/international-components-for-unicode--icu-
[2]: Put PR link to MS STL 1789 here.
[3]: https://techcommunity.microsoft.com/category/windows/blog/dstblog
[4]: https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time_zone_information
[5]: https://stackoverflow.com/a/47106207
0 commit comments