Incorrect transition times in std::chrono::time_zone::get_info()
Edward Welbourne
edward.welbourne@qt.io
Fri Jul 26 13:07:32 GMT 2024
>> Jonathan Wakely (26 July 2024 12:41) replied:
>> > What exactly is the problem you see? Do you have a testcase for this?
On Fri, 26 Jul 2024 at 11:56, Edward Welbourne <edward.welbourne@qt.io> wrote:
>> 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.
Jonathan Wakely (26 July 2024 13:40) replied:
> I replaced idToZone with chrono::locate_zone just because.
Fair enough, I think we had the binary chop to avoid having to
deal with exceptions in builds without them.
> Your sys_time is greater than sys_days(year::max()/January/1), so I
> think libstdc++ gives up calculating transitions past that point and
> can't give you the info.
>
> I find it hard to be motivated to support get_info past the 33rd
> millennium, I don't expect this code to still be in use by the time of
> the Horus Heresy.
and, as I noted before, we can live with that - even year::max() beats
the socks off a certain other platform which shall remain unnamed, so I
have kludges in place to take care of out-of-bounds.
>> > 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.
> But not within the chrono::year::max() upper limit.
That's the sort of bound I'd begun to suspect, nice to have it pinned down.
> I could add an explicit check for times past that limit and give a
> better what() in the exception (and not bother calculating 64 thousand
> transitions before realising the requested time point is still too
> high).
I'm surprised you compute all intervening transitions, rather than just
jumping straight to the final year (and, in this case, recognising
you're out of bounds).
>> > 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.
[snip]
>> > 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.
> For example, this one:
> Asia/Bishkek : 2005-08-12 06:00:00 +06
> The transition in that case is:
> 5 KG +05/+06 2005 Au 12
> 6 - +06
> Since the UNTIL field is just Au 12 without a TIME, it occurred at
> midnight, but it should be midnight standard time, not midnight UTC.
> So it's the same bug.
Sounds like there's no point me fighting my way past the "User account
creation has been restricted" that I hit when trying to create an
account, then, since you already have it in your sights.
I note that in tz/asia the entry is (with apologies for a certain mailer I
did not chose probably messing up the formatting):
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Asia/Bishkek 4:58:24 - LMT 1924 May 2
5:00 - +05 1930 Jun 21
6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s
5:00 RussiaAsia +05/+06 1991 Aug 31 2:00
5:00 Kyrgyz +05/+06 2005 Aug 12
6:00 - +06
so I guess you're working with a pre-digested form of it. The Kyrgyz
rule it references appears just before this,
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
Rule Kyrgyz 1992 1996 - Apr Sun>=7 0:00s 1:00 -
Rule Kyrgyz 1992 1996 - Sep lastSun 0:00 0 -
Rule Kyrgyz 1997 2005 - Mar lastSun 2:30 1:00 -
Rule Kyrgyz 1997 2004 - Oct lastSun 2:30 0 -
and gives no AT for 2005 Aug, although its 2:30 transition times in
March and October, each ending before it, are suggestive. The lack of a
specified transition time may not be as simple as midnight - there are
some entries that specify 0:00 overtly as transition time
(e.g. Europe/Brussels in 1916), which they probably wouldn't if it were
the default - but I don't know what the actual rule is. The only
documentation I can find is the tz-how-to.html in the tz repo [0] and
it's a bit incomplete. Consulting others who maintain parsers for this
format, or their parser source-code, is probably the only option.
[0] https://github.com/eggert/tz
Eddy.
More information about the Libstdc++
mailing list