Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2222413/?format=api
{ "id": 2222413, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2222413/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/145d8b8b89cfeba3cbfe9b60c55af783a51d17fc.1775912642.git.alvaro.begue@gmail.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/1.2/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<145d8b8b89cfeba3cbfe9b60c55af783a51d17fc.1775912642.git.alvaro.begue@gmail.com>", "list_archive_url": null, "date": "2026-04-11T13:33:06", "name": "[2/5] libstdc++: Support ON-format DAY in Zone UNTIL field [PR 124852]", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "79354a055306ea610f1b8cdc835020c554c64bab", "submitter": { "id": 93119, "url": "http://patchwork.ozlabs.org/api/1.2/people/93119/?format=api", "name": "Alvaro Begue", "email": "alvaro.begue@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/145d8b8b89cfeba3cbfe9b60c55af783a51d17fc.1775912642.git.alvaro.begue@gmail.com/mbox/", "series": [ { "id": 499557, "url": "http://patchwork.ozlabs.org/api/1.2/series/499557/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=499557", "date": "2026-04-11T13:33:04", "name": "libstdc++: chrono tzdb correctness fixes", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/499557/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2222413/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2222413/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=XuC/4U9B;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=XuC/4U9B", "sourceware.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com", "sourceware.org; spf=pass smtp.mailfrom=gmail.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=209.85.219.46" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4ftF5267mGz1yCx\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 11 Apr 2026 23:34:14 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id F337E4BA23FF\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 11 Apr 2026 13:34:12 +0000 (GMT)", "from mail-qv1-f46.google.com (mail-qv1-f46.google.com\n [209.85.219.46])\n by sourceware.org (Postfix) with ESMTPS id 3F9B24BA23DD\n for <gcc-patches@gcc.gnu.org>; Sat, 11 Apr 2026 13:33:30 +0000 (GMT)", "by mail-qv1-f46.google.com with SMTP id\n 6a1803df08f44-8a154cc6a48so32757836d6.0\n for <gcc-patches@gcc.gnu.org>; Sat, 11 Apr 2026 06:33:30 -0700 (PDT)", "from alvaro-MS-7D37.verizon.net\n ([2600:4041:592d:7300:b8f7:c631:1ab:88b0])\n by smtp.gmail.com with ESMTPSA id\n 6a1803df08f44-8ac84caace4sm47629306d6.39.2026.04.11.06.33.28\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Sat, 11 Apr 2026 06:33:28 -0700 (PDT)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org F337E4BA23FF", "OpenDKIM Filter v2.11.0 sourceware.org 3F9B24BA23DD" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 3F9B24BA23DD", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 3F9B24BA23DD", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775914410; cv=none;\n b=YbapCbsyUJM/dz4zd0FWtlXQ5/hYX7K7T5kFHcnTkkFSPYrynjnheTN4ytGHZikNQzrdg18A74MacNPS9uamF5IIzbo+gE5Efssm8R3v0qqBJ0Tntk1aNNy3uYE4sietxmrjptwNk1BcayWlfJP7Alo5gn+HGL6eRPOTloI9HQc=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1775914410; c=relaxed/simple;\n bh=criBu4JDWgFiqbhPlOfGX7fCJAlKEVxGpk5s8y+43T8=;\n h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version;\n b=kWwB8SrNvrVG1aDkLJG0uIbNbyH9sM/whFR6EUfDvSAZCR97baNs1SaQtEDHZAtdM670/6ZmV7mrOumbGWevcJBF0/Iy7S0S8UbVcdgc2n4ZYBEiBip8y+PsgLtyk1sOzO3oIIJeGqN3zcSpMQXySoHqthmuAeARko1bv39NlM8=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1775914409; x=1776519209; darn=gcc.gnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=tZnWloUK7RNx0e7K4HDbnnD8j67gszig8njZMuYQ/r8=;\n b=XuC/4U9BJAW7jHowECqnl8MogT28Y0gaSx8mzqcMlXIO36DeSWQdhKhmg3E3rIQ9MM\n +BMn+Gv/hEnTnaW5s2aYokWr2im3nqJonoVbXCINQS3p4CD8UaiPYPGw1oHwDphcKNR9\n qJJTIXhE3jJq5K1Kh26cPX51lwtOKK2O3xhqJSdsftuvpkdutMagZaswHcqtsUwILSuU\n JVTiNYoZ74oAaQeQ4EV5E9Hm3ozrcNPb8fTzVSaYgsY1dwX2V1eMoKjPLaPbwE0kD5qW\n t5eiulHK8+vwcaT/mUdiNIsMNkIMyOKw5UD8TJgj9imQa7qh4NcCB99J72vxqmeKUgR1\n YAsA==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775914409; x=1776519209;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=tZnWloUK7RNx0e7K4HDbnnD8j67gszig8njZMuYQ/r8=;\n b=rcWutl0tO2ZVPYHnEY799b8x8zyOM7gBitjYHljJ0V6pd0qg0V066pgWy4mZ2tebd2\n oQPG9DOeGToHYFKv7s53y/Meivu1YiseETAUvkXzTYIQVgDo0bflmuZ/B0W0zDMdPPre\n sj5n0xguko+hZay2HDCTFlUc3/33WLnW7ClNFc3gM/VALmHwPjx6QJHi6eo+is4Lk6ih\n cpYTGcjFg2M3hdNtjaM4/i8qTZD1x09OOMCCHtjpJNqjvnOct9pR6WS4mIVeX4McmG/0\n HeJ1Pu/WhEKhZC53G9NkJlvmdNLgRoE9F8sQVCnZmf01J8hDeGxQz1T6cy1gn4IGmy6h\n M1+Q==", "X-Gm-Message-State": "AOJu0YxTF2ljkjD8KGRtVQO/bgw4TgmaqcQ9qazzWXIDQfqbUPTunZGU\n k8B4TMh0JMW/K2SSf65+CQxbv4bUMrqFr1ro7aIaHLOXe6dJIPl85Qnp3VnEzg==", "X-Gm-Gg": "AeBDies/bKtM9FmMFtL8lmfmQysVLjovdWVUE6Kr6Q/AAB8FzXMBFmZ9UQZcA2DO3c5\n OJuCN1vsfiUmfjKERr8j1zdyVG7LZLvPDjvpWzQoQNfy4oiE08e2U11Do42wx7qWwGQJ25rOUuo\n NYqLgfmlxAmLpGd+EJ5jxvy0g6Rco58tXTHELiIU3ECqaf5NPZAlDSPQd6NRRHQYS3q5tij7AN2\n CZv+OuiVpY9cDn8ln1yuvxLpqq/dNmoVyPLviJGg122cWT3xSBMyOjW7ydg5BOcnjtmhHnC4il0\n 9eXt6tQ+66OiZkXi52nFREbaJnDPGAy9OoZoYWq1mfsDhKh1AYlywFgjgGp8IZupfMW6zPc4vzX\n +q2APed4+AEAT7HvKaVq9+SZajn9rNvO+RQ05Psfu8f6kIRcx2aCKsIYbNOM36WMoMLl2ke5vox\n 8BJsY+ih0wkwf9hCMt1SE2NeUfZZamQfS6NMe2I7tffj2MYzSSBEigqKRFywz+EMd0AzLwrGCcm\n YJXIm4WBJY+KFEB3LEDiLWgRkseW6Ps5PoSrZz1SAt0aS6qTaBZMXtDCRgqhgeEMHSifi0X89sz\n BX3M", "X-Received": "by 2002:a05:6214:5781:b0:8ac:8337:ca0f with SMTP id\n 6a1803df08f44-8ac8625d5d5mr107424336d6.29.1775914409291;\n Sat, 11 Apr 2026 06:33:29 -0700 (PDT)", "From": "Alvaro Begue <alvaro.begue@gmail.com>", "To": "gcc-patches@gcc.gnu.org", "Cc": "jwakely@redhat.com, libstdc++@gcc.gnu.org,\n Alvaro Begue <alvaro.begue@gmail.com>", "Subject": "[PATCH 2/5] libstdc++: Support ON-format DAY in Zone UNTIL field [PR\n 124852]", "Date": "Sat, 11 Apr 2026 09:33:06 -0400", "Message-Id": "\n <145d8b8b89cfeba3cbfe9b60c55af783a51d17fc.1775912642.git.alvaro.begue@gmail.com>", "X-Mailer": "git-send-email 2.34.1", "In-Reply-To": "<cover.1775912642.git.alvaro.begue@gmail.com>", "References": "<cover.1775912642.git.alvaro.begue@gmail.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "The Zone-line UNTIL parser only accepted a plain day-of-month integer\nfor the DAY field, while the tzdata.zi grammar accepts the same ON-style\nforms as Rule lines: lastSun, Sun>=8, Sat<=20, etc. Real zones use these\nforms in their UNTIL DAY: Europe/Simferopol's `3 - MSK 1997 Mar lastSu\n1u`, for instance, became `Mar 1` (silently misparsed) instead of `Mar\n30`, leaving Simferopol an extra 29 days in MSK.\n\nThe previous parser's `int d = 1; in >> m >> d >> t;` chain silently\nleft d == 1 when the day token wasn't a digit, then went on to parse the\nremainder as the TIME field.\n\nFix by reusing the existing parse_on_day_body() helper that already\nhandles all three on_day forms (DayOfMonth, LastWeekday, LessEq /\nGreaterEq) for Rule lines. The MONTH-only and YEAR-only short forms are\nstill accepted because the DAY/TIME fields are optional and default to\nday 1, time 00:00. The on_day struct's pin() method handles the\nyear/month-relative resolution.\n\nThe DAY field is unambiguously distinguishable from a TIME field that\ncould otherwise follow the MONTH directly: per zic's grammar, MONTH\nmust be followed by DAY before any TIME is allowed. So we always\nattempt to parse a DAY if any non-whitespace remains after the MONTH.\n\nlibstdc++-v3/ChangeLog:\n\n\tPR libstdc++/124852\n\t* src/c++20/tzdb.cc (parse_on_day_body): Factor out the day-\n\tcomponent parser from operator>>(istream&, on_day&) so it can\n\tbe reused.\n\t(operator>>(istream&, on_day&)): Use the new helper.\n\t(operator>>(istream&, ZoneInfo&)): Replace the integer DAY\n\tparser with parse_on_day_body for the UNTIL field.\n\t* testsuite/std/time/time_zone/until_day_on.cc: New test.\n---\n libstdc++-v3/src/c++20/tzdb.cc | 55 ++++--\n .../std/time/time_zone/until_day_on.cc | 177 ++++++++++++++++++\n 2 files changed, 217 insertions(+), 15 deletions(-)\n create mode 100644 libstdc++-v3/testsuite/std/time/time_zone/until_day_on.cc", "diff": "diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc\nindex 33217f0a9..8cbf3213d 100644\n--- a/libstdc++-v3/src/c++20/tzdb.cc\n+++ b/libstdc++-v3/src/c++20/tzdb.cc\n@@ -2204,22 +2204,24 @@ namespace std::chrono\n }\n };\n \n- istream& operator>>(istream& in, on_day& to)\n+ // Read the day-component of an on_day expression (everything after the\n+ // month). Three forms are accepted: a plain day-of-month number,\n+ // \"lastXxx\" where Xxx is a weekday name (LastWeekday), or \"Xxx<=N\" or\n+ // \"Xxx>=N\" (LessEq / GreaterEq). The caller is responsible for setting\n+ // `on.month` before calling. On failure the function sets failbit and\n+ // leaves `on` unchanged.\n+ istream&\n+ parse_on_day_body(istream& in, on_day& on)\n {\n- on_day on{};\n- abbrev_month m{};\n- in >> m;\n- on.month = static_cast<unsigned>(m.m);\n int c = ws(in).peek();\n if ('0' <= c && c <= '9')\n \t{\n-\t on.kind = on_day::DayOfMonth;\n \t unsigned d;\n \t in >> d;\n \t if (d <= 31) [[likely]]\n \t {\n+\t on.kind = on_day::DayOfMonth;\n \t on.day_of_month = d;\n-\t to = on;\n \t return in;\n \t }\n \t}\n@@ -2230,7 +2232,6 @@ namespace std::chrono\n \t {\n \t on.kind = on_day::LastWeekday;\n \t on.day_of_week = w.wd.c_encoding();\n-\t to = on;\n \t return in;\n \t }\n \t}\n@@ -2242,14 +2243,13 @@ namespace std::chrono\n \t {\n \t if (in.get() == '=')\n \t\t{\n-\t\t on.kind = c == '<' ? on_day::LessEq : on_day::GreaterEq;\n-\t\t on.day_of_week = w.wd.c_encoding();\n \t\t unsigned d;\n \t\t in >> d;\n \t\t if (d <= 31) [[likely]]\n \t\t {\n+\t\t on.kind = c == '<' ? on_day::LessEq : on_day::GreaterEq;\n+\t\t on.day_of_week = w.wd.c_encoding();\n \t\t on.day_of_month = d;\n-\t\t to = on;\n \t\t return in;\n \t\t }\n \t\t}\n@@ -2259,6 +2259,17 @@ namespace std::chrono\n return in;\n }\n \n+ istream& operator>>(istream& in, on_day& to)\n+ {\n+ on_day on{};\n+ abbrev_month m{};\n+ in >> m;\n+ on.month = static_cast<unsigned>(m.m);\n+ if (parse_on_day_body(in, on))\n+\tto = on;\n+ return in;\n+ }\n+\n istream& operator>>(istream& in, at_time& at)\n {\n int sign = 1;\n@@ -2362,11 +2373,25 @@ namespace std::chrono\n if (int y = int(year::max()); in >> y)\n \t{\n \t abbrev_month m{January};\n-\t int d = 1;\n+\t on_day on{};\n+\t on.kind = on_day::DayOfMonth;\n+\t on.month = 1; // default January\n+\t on.day_of_month = 1; // default day-of-month 1\n \t at_time t{};\n-\t // XXX DAY should support ON format, e.g. lastSun or Sun>=8\n-\t in >> m >> d >> t;\n-\t inf.m_until = sys_days(year(y)/m.m/day(d)) + seconds(t.time);\n+\t if (in >> m)\n+\t {\n+\t on.month = static_cast<unsigned>(m.m);\n+\t // The DAY field is optional. Per the tzdata.zi grammar,\n+\t // a MONTH followed by anything more is always followed by\n+\t // a DAY (possibly followed by a TIME); MONTH directly\n+\t // followed by TIME is not a valid form. So if there's\n+\t // any non-whitespace before end of line, parse a DAY.\n+\t if (!ws(in).eof())\n+\t\tparse_on_day_body(in, on);\n+\t }\n+\t in >> t;\n+\t year_month_day ymd = on.pin(year(y));\n+\t inf.m_until = sys_days(ymd) + seconds(t.time);\n \t if (t.indicator != at_time::Universal)\n \t { // UNTIL uses \"the rules in effect just before the transition\"\n \t // adjust by STDOFF\ndiff --git a/libstdc++-v3/testsuite/std/time/time_zone/until_day_on.cc b/libstdc++-v3/testsuite/std/time/time_zone/until_day_on.cc\nnew file mode 100644\nindex 000000000..cf9e51d26\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/std/time/time_zone/until_day_on.cc\n@@ -0,0 +1,177 @@\n+// { dg-do run { target c++20 } }\n+// { dg-require-effective-target tzdb }\n+// { dg-require-effective-target cxx11_abi }\n+// { dg-xfail-run-if \"no weak override on AIX\" { powerpc-ibm-aix* } }\n+\n+// Regression test: the DAY portion of a Zone line's UNTIL field accepts\n+// not only a numeric day-of-month but also \"lastXxx\" (last weekday in\n+// the month) and \"Xxx<=N\" / \"Xxx>=N\" forms, just like the ON field of\n+// a Rule line. Previously the UNTIL parser used `int d; in >> d;` which\n+// silently failed on the non-numeric forms and defaulted d to 1, placing\n+// any zone-line transition with such an UNTIL on the wrong calendar day.\n+//\n+// Real-world example: Europe/Simferopol has\n+// 3 - MSK 1997 Mar lastSu 1u\n+// which must place the boundary on 1997-03-30 (the last Sunday of March),\n+// not on 1997-03-01.\n+\n+#include <chrono>\n+#include <fstream>\n+#include <testsuite_hooks.h>\n+\n+static bool override_used = false;\n+\n+namespace __gnu_cxx\n+{\n+ const char* zoneinfo_dir_override() {\n+ override_used = true;\n+ return \"./\";\n+ }\n+}\n+\n+void\n+test_lastsu()\n+{\n+ using namespace std::chrono;\n+\n+ std::ofstream(\"tzdata.zi\") << R\"(# version test_lastsu\n+Z Test/LastSu 3 - MSK 1997 Mar lastSu 1u\n+ 3 - X\n+)\";\n+\n+ const auto& db = reload_tzdb();\n+ VERIFY( override_used );\n+ VERIFY( db.version == \"test_lastsu\" );\n+\n+ auto* tz = locate_zone(\"Test/LastSu\");\n+\n+ // True boundary: 1997-03-30 01:00 UTC (lastSu of March 1997 is Mar 30,\n+ // and the indicator is 'u' = Universal so no offset adjustment).\n+ sys_seconds boundary = sys_days{1997y/March/30} + 1h;\n+\n+ // Just before: still in the MSK line.\n+ auto before = tz->get_info(boundary - 1s);\n+ VERIFY( before.abbrev == \"MSK\" );\n+ VERIFY( before.offset == 3h );\n+\n+ // At/after the boundary: in the X line.\n+ auto at = tz->get_info(boundary);\n+ VERIFY( at.abbrev == \"X\" );\n+\n+ // Critical regression check: a sample 15 days BEFORE the boundary must\n+ // still be in the MSK line. The unfixed parser placed the boundary on\n+ // March 1 because \"lastSu\" defaulted to day 1, and a March-15 query\n+ // landed in the X line instead.\n+ auto mid_march = tz->get_info(sys_days{1997y/March/15});\n+ VERIFY( mid_march.abbrev == \"MSK\" );\n+ VERIFY( mid_march.offset == 3h );\n+}\n+\n+void\n+test_sun_ge_n()\n+{\n+ using namespace std::chrono;\n+\n+ std::ofstream(\"tzdata.zi\") << R\"(# version test_sun_ge_n\n+Z Test/SunGE 0 - A 1990 Jun Sun>=8 0u\n+ 0 - B\n+)\";\n+\n+ const auto& db = reload_tzdb();\n+ VERIFY( override_used );\n+ VERIFY( db.version == \"test_sun_ge_n\" );\n+\n+ auto* tz = locate_zone(\"Test/SunGE\");\n+\n+ // First Sunday >= June 8 1990 = June 10 (June 8 1990 was a Friday).\n+ sys_seconds boundary = sys_days{1990y/June/10};\n+\n+ auto before = tz->get_info(boundary - 1s);\n+ VERIFY( before.abbrev == \"A\" );\n+ auto at = tz->get_info(boundary);\n+ VERIFY( at.abbrev == \"B\" );\n+\n+ // A June-1 query must still be in the A line (the unfixed parser\n+ // placed the boundary on June 1).\n+ auto early = tz->get_info(sys_days{1990y/June/1});\n+ VERIFY( early.abbrev == \"A\" );\n+}\n+\n+void\n+test_sun_le_n()\n+{\n+ using namespace std::chrono;\n+\n+ std::ofstream(\"tzdata.zi\") << R\"(# version test_sun_le_n\n+Z Test/SunLE 0 - A 1990 Jun Sun<=15 0u\n+ 0 - B\n+)\";\n+\n+ const auto& db = reload_tzdb();\n+ VERIFY( override_used );\n+ VERIFY( db.version == \"test_sun_le_n\" );\n+\n+ auto* tz = locate_zone(\"Test/SunLE\");\n+\n+ // Last Sunday <= June 15 1990 = June 10.\n+ sys_seconds boundary = sys_days{1990y/June/10};\n+\n+ auto before = tz->get_info(boundary - 1s);\n+ VERIFY( before.abbrev == \"A\" );\n+ auto at = tz->get_info(boundary);\n+ VERIFY( at.abbrev == \"B\" );\n+}\n+\n+void\n+test_year_only()\n+{\n+ using namespace std::chrono;\n+\n+ // Sanity check: a UNTIL with only a year (no MONTH, no DAY, no TIME)\n+ // must continue to default to January 1 00:00.\n+ std::ofstream(\"tzdata.zi\") << R\"(# version test_year_only\n+Z Test/YearOnly 0 - A 1990\n+ 0 - B\n+)\";\n+\n+ const auto& db = reload_tzdb();\n+ VERIFY( db.version == \"test_year_only\" );\n+\n+ auto* tz = locate_zone(\"Test/YearOnly\");\n+ auto before = tz->get_info(sys_days{1989y/December/31} + 23h);\n+ VERIFY( before.abbrev == \"A\" );\n+ auto at = tz->get_info(sys_days{1990y/January/1});\n+ VERIFY( at.abbrev == \"B\" );\n+}\n+\n+void\n+test_year_month_only()\n+{\n+ using namespace std::chrono;\n+\n+ // Sanity check: UNTIL with only YEAR and MONTH (no DAY, no TIME)\n+ // must default DAY to 1 and TIME to 00:00.\n+ std::ofstream(\"tzdata.zi\") << R\"(# version test_year_month_only\n+Z Test/YearMonth 0 - A 1990 Jul\n+ 0 - B\n+)\";\n+\n+ const auto& db = reload_tzdb();\n+ VERIFY( db.version == \"test_year_month_only\" );\n+\n+ auto* tz = locate_zone(\"Test/YearMonth\");\n+ auto before = tz->get_info(sys_days{1990y/June/30} + 23h);\n+ VERIFY( before.abbrev == \"A\" );\n+ auto at = tz->get_info(sys_days{1990y/July/1});\n+ VERIFY( at.abbrev == \"B\" );\n+}\n+\n+int\n+main()\n+{\n+ test_lastsu();\n+ test_sun_ge_n();\n+ test_sun_le_n();\n+ test_year_only();\n+ test_year_month_only();\n+}\n", "prefixes": [ "2/5" ] }