Incorrect transition times in std::chrono::time_zone::get_info()
Edward Welbourne
edward.welbourne@qt.io
Fri Jul 26 10:56:13 GMT 2024
On Fri, 26 Jul 2024 at 11:04, Edward Welbourne <edward.welbourne@qt.io> wrote:
>> One issue is that the supported range of times is rather limited; Qt
>> uses a 64-bit signed count of milliseconds from the UTC start of
>> 1970, which does admittedly have an insanely wide range, but (I am
>> happy to report) glibc's time_t functions seem to cope with that
>> whole range just fine.
Jonathan Wakely (26 July 2024 12:41) replied:
> For a 64-bit time_t they'll have an even larger range, since they'll
> work with a 64-bit signed number of seconds, not milliseconds.
>
> For 32-bit time_t, you have bigger problems anyway.
Indeed, but the Qt code knows about that and kludges round it.
>> However, the std::chrono::time_zone::get_info() range is
>> considerably narrower (I haven't yet pinned down its limits). That's
>> bearable, since the out-of-range times are of course only ever seen in
>> artificial test-cases; and get_info() raises a std::runtime_error for
>> out-of-range values, so we can catch that and cope by other kludges
>> (that we need on other platforms anyway).
> What exactly is the problem you see? Do you have a testcase for this?
static void lateInfo(void)
{
using namespace std::chrono;
constexpr long long huge = 0x7fffffffffffffff;
constexpr auto late = sys_time<milliseconds>(milliseconds(huge));
const time_zone *zone = idToZone("Europe/Oslo");
const sys_info info = zone->get_info(late); // std::runtime_error
std::cout << '\n' << info.abbrev << '\n';
}
Slap a call to this into the start of my previous main(), for example,
to see the exception thrown. It's using the same idToZone() as before.
> time_zone::get_info converts its argument to sys_seconds and calls
> _M_get_sys_info. That should have exactly the same range as time_t
> (64-bit signed number of seconds, with 1970-01-01 as the epoch).
I'm on a 64-bit system, where the time_t functions cope with times such
as the one above, and this is a 64-bit number of milliseconds out, so
should be well within a 64-bit second range.
> There's a known bug (well, known to me) where libstdc++ should
> inerpret the transition time relative to the current wall clock time,
> not UTC. There are a couple of relevant comments in the code:
>
> // XXX The ri.until() time point should be
> // "interpreted using the rules in effect just before the transition"
> info.end = ri.until();
>
> // XXX UNTIL field should be interpreted
> // "using the rules in effect just before the transition"
> // so might need to store as year_month_day and hh_mm_ss and only
> // convert to a sys_time once we know the offset in effect.
> inf.m_until = sys_days(year(y)/m.m/day(d)) + seconds(t.time);
That matches my suspicions.
> So if a transition should happen at (for example) 2am local time,
> libstdc++ might be applying it at 2am UTC in some cases.
That fits some of the cases in the list I gave before.
Others seem to be using UTC 00:00.
>> So I first want to check whether I'm using the API right and, if so, to
> I'll take a look at your testcase and check if it matches my
> understanding.
Thanks - I'm relatively new to the C++20 tzdb stuff, so won't be
entirely surprised if I've got some crossed wires.
>> know where to report the bug.
> All libstdc++ bugs should be reported in GCC's bugzilla.
Duly noted, thanks - and thanks for the prompt reply,
Eddy.
More information about the Libstdc++
mailing list