libstdc++: Implement zic writezone merge optimization [PR124854]

When two adjacent Zone lines have different total offsets and the
new line's rule set has a rule firing within jump of the boundary
(where jump = old_total - new_total > 0, i.e. local time goes
backward at the boundary), zic folds that rule into the boundary
itself: the single transition emitted has the rule's save value
already applied, so the new line begins with the post-rule save
rather than briefly using the pre-rule save and then transitioning
again moments later.

Canonical examples handled by the new merge block:
* America/Argentina/Buenos_Aires 1999-10-03: lines change
  stdoff -3 → -4 with an Argentina DST rule firing on the same
  day. Without the merge, chrono emits a 1-hour stretch of
  offset=-4 save=0 and then transitions to offset=-3 save=1;
  with the merge, the boundary itself is at offset=-3 save=1.
* Europe/Berlin 1945-05-24: lines split a rule set, with the
  So 1945-May-24 rule (save=2, "CEMT") firing at 01:00 UTC in
  the new frame, inside the 1h backward window.

Similarly, when the zone expansion algorithm is resumed after DST
span (save = 1h), we will revisit the corresponding STD transition,
for example: given offset +2h, the transition happening at 12:00
local time, will be considered twice:
 * 09:00 UT (2h + 1h) - proper ending of DST span
 * 10:00 UT (2h) - after re-entry.
Previously this transition were rejected using the (now removed)
rule_start - t < days(1) check, preventing us from emitting the one
hour STD time range followed by rest of same range. In this patch,
we reuse same merge logic, as such STD transition happens during
backward jump from boundary introduced by previous expansion.

This patch address both of the above by computing length of the
backward jump (merge_window) at the start of the expansion (regardless
if initial or re-entry), and then considering initial rule transition
happening in [info.begin + merge_window] to apply at info.begin.

libstdc++-v3/ChangeLog:

	PR libstdc++/124854
	* src/c++20/tzdb.cc (ZoneInfo::save): Define.
	(time_zone::_M_get_sys_info): Fold initial transition if they
	occurs in duplicated local time window (merge_window) due move
	from DST to STD zone.
	* testsuite/std/time/time_zone/wall_cascade.cc (test_next_year):
	Test that 1945 Pacific/Auckland transition is properly handled.
	(test_negative): Adjust test to avoid zone merge.
	* testsuite/std/time/time_zone/zone_merge.cc: New test.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Co-authored-by: Álvaro Begué <alvaro.begue@gmail.com>
Signed-off-by: Álvaro Begué <alvaro.begue@gmail.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
3 files changed