Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kopeninghours for openSUSE:Factory checked in at 2021-08-16 10:10:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kopeninghours (Old) and /work/SRC/openSUSE:Factory/.kopeninghours.new.1899 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kopeninghours" Mon Aug 16 10:10:28 2021 rev:5 rq:911722 version:21.08.0 Changes: -------- --- /work/SRC/openSUSE:Factory/kopeninghours/kopeninghours.changes 2021-07-10 00:01:57.951299012 +0200 +++ /work/SRC/openSUSE:Factory/.kopeninghours.new.1899/kopeninghours.changes 2021-08-16 10:16:00.138773327 +0200 @@ -1,0 +2,38 @@ +Fri Aug 6 09:40:09 UTC 2021 - Christophe Giboudeaux <[email protected]> + +- Update to 21.08.0 + * New feature release + * For more details please see: + * https://kde.org/announcements/gear/21.08/ +- No code change since 21.07.90 + +------------------------------------------------------------------- +Fri Jul 30 10:05:21 UTC 2021 - Christophe Giboudeaux <[email protected]> + +- Update to 21.07.90 + * New feature release +- No code change since 21.07.80 + +------------------------------------------------------------------- +Sat Jul 17 20:06:29 UTC 2021 - Christophe Giboudeaux <[email protected]> + +- Update to 21.07.80 + * New feature release +- Changes since 21.04.3: + * Migrate to new REUSE CI check + * Fix invalid simplification on wrapped weekday selectors + * Work around qmlplugindump choking on gadget singletons + * Fix crash in simplifiedExpression for a null expression + * Simplify weekday lists: Mo,Tu,We => Mo-We + * Add support for a dot after short weekday names (Mo. Tu. We. etc.) + * Add support for "whitsun +1 day", should be "easter +50 days" + * Add support for non-standard "whitsun" = easter +49 days + * Also perform simplification in the command line validation tool + * The recent commit "generalize to comma" was about a simplification. + * Add simplifiedExpression() + * Generalize time-only-autocorrect to work with ',' as well. + * Fix crash in my recently-added autocorrect check + * autocorrect wrong use of ';' where ',' was expected +- Only install the license files once + +------------------------------------------------------------------- Old: ---- kopeninghours-21.04.3.tar.xz kopeninghours-21.04.3.tar.xz.sig New: ---- kopeninghours-21.08.0.tar.xz kopeninghours-21.08.0.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kopeninghours.spec ++++++ --- /var/tmp/diff_new_pack.JuXRVU/_old 2021-08-16 10:16:00.546772836 +0200 +++ /var/tmp/diff_new_pack.JuXRVU/_new 2021-08-16 10:16:00.546772836 +0200 @@ -18,7 +18,7 @@ %bcond_without lang Name: kopeninghours -Version: 21.04.3 +Version: 21.08.0 Release: 0 Summary: OSM opening hours expression parser and evaluator License: LGPL-2.0-or-later @@ -78,7 +78,6 @@ %postun -n libKOpeningHours1 -p /sbin/ldconfig %files -%license LICENSES/* %dir %{_kf5_qmldir}/org %dir %{_kf5_qmldir}/org/kde %{_kf5_qmldir}/org/kde/kopeninghours/ @@ -89,7 +88,6 @@ %{_kf5_libdir}/libKOpeningHours.so.* %files devel -%license LICENSES/* %{_includedir}/KOpeningHours/ %{_includedir}/kopeninghours/ %{_includedir}/kopeninghours_version.h ++++++ kopeninghours-21.04.3.tar.xz -> kopeninghours-21.08.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/.gitlab-ci.yml new/kopeninghours-21.08.0/.gitlab-ci.yml --- old/kopeninghours-21.04.3/.gitlab-ci.yml 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/.gitlab-ci.yml 2021-08-04 23:42:48.000000000 +0200 @@ -1,9 +1,5 @@ # SPDX-FileCopyrightText: 2020 Volker Krause <[email protected]> # SPDX-License-Identifier: CC0-1.0 -reuse: - image: - name: fsfe/reuse:latest - entrypoint: [""] - script: - - reuse lint +include: + - https://invent.kde.org/sysadmin/ci-tooling/raw/master/invent/ci-reuse.yml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/CMakeLists.txt new/kopeninghours-21.08.0/CMakeLists.txt --- old/kopeninghours-21.04.3/CMakeLists.txt 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/CMakeLists.txt 2021-08-04 23:42:48.000000000 +0200 @@ -5,8 +5,8 @@ # KDE Application Version, managed by release script set (RELEASE_SERVICE_VERSION_MAJOR "21") -set (RELEASE_SERVICE_VERSION_MINOR "04") -set (RELEASE_SERVICE_VERSION_MICRO "3") +set (RELEASE_SERVICE_VERSION_MINOR "08") +set (RELEASE_SERVICE_VERSION_MICRO "0") set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}") project(KOpeningHours VERSION ${RELEASE_SERVICE_VERSION}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/autotests/parsertest.cpp new/kopeninghours-21.08.0/autotests/parsertest.cpp --- old/kopeninghours-21.04.3/autotests/parsertest.cpp 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/autotests/parsertest.cpp 2021-08-04 23:42:48.000000000 +0200 @@ -18,9 +18,11 @@ { QTest::addColumn<QByteArray>("input"); QTest::addColumn<QByteArray>("expectedOutput"); + QTest::addColumn<QByteArray>("expectedSimplifiedOutput"); -#define T(x) QTest::newRow(x) << QByteArray(x) << QByteArray(x) -#define T2(x, y) QTest::newRow(x) << QByteArray(x) << QByteArray(y) +#define T(x) QTest::newRow(x) << QByteArray(x) << QByteArray(x) << QByteArray(x) +#define T2(x, y) QTest::newRow(x) << QByteArray(x) << QByteArray(y) << QByteArray(y) +#define T3(x, y, z) QTest::newRow(x) << QByteArray(x) << QByteArray(y ? y : x) << QByteArray(z) T("24/7"); T("24/7 \"comment\""); T("24/7 closed"); @@ -41,6 +43,8 @@ T("easter off"); T("easter +1 day off"); T("easter -2 days off"); + T2("whitsun off", "easter +49 days off"); + T2("whitsun +1 day off", "easter +50 days off"); T("2020"); T("2020-2021"); T("1970-2022/2"); @@ -71,13 +75,15 @@ T2("Dec 01 -Su 08:00-12:00", "Dec 01 Su[-1] 08:00-12:00"); T("Aug Mo[1]-Aug Sa[-1] closed"); T("2020/2"); - T("\"Au??erhalb der Semesterferien\": Mo-Fr 08:00-22:00; Sa-Su 10:00-20:00; \"Innerhalb der Semesterferien\": Mo-Fr 08:00-18:00; Sa-Su 10:00-16:00"); + T("\"Au??erhalb der Semesterferien\": Mo-Fr 08:00-22:00; Sa,Su 10:00-20:00; \"Innerhalb der Semesterferien\": Mo-Fr 08:00-18:00; Sa,Su 10:00-16:00"); T("PH Mo-Th 14:00-23:00"); T2("Mo-Th PH 14:00-23:00", "PH Mo-Th 14:00-23:00"); T("PH Fr,SH Fr 11:30-02:00"); T2("PH Fr, SH Fr 11:30-02:00", "PH Fr,SH Fr 11:30-02:00"); T2("PH Th,Fr, SH Tu,Fr 11:30-02:00", "PH Th,Fr,SH Tu,Fr 11:30-02:00"); - T2("Mo-Th 17:00-23:00, Mo-Th SH 14:00-23:00, Fr 14:00-02:00, Sa 11:30-22:00, Su 11:30-22:00, PH Mo-Th 11:30-23:00, PH Fr, SH Fr 11:30-02:00, PH Sa-Su 11:30-22:00", "Mo-Th 17:00-23:00, SH Mo-Th 14:00-23:00, Fr 14:00-02:00, Sa 11:30-22:00, Su 11:30-22:00, PH Mo-Th 11:30-23:00, PH Fr,SH Fr 11:30-02:00, PH Sa-Su 11:30-22:00"); + T3("Mo-Th 17:00-23:00, Mo-Th SH 14:00-23:00, Fr 14:00-02:00, Sa 11:30-22:00, Su 11:30-22:00, PH Mo-Th 11:30-23:00, PH Fr, SH Fr 11:30-02:00, PH Sa-Su 11:30-22:00", + "Mo-Th 17:00-23:00, SH Mo-Th 14:00-23:00, Fr 14:00-02:00, Sa 11:30-22:00, Su 11:30-22:00, PH Mo-Th 11:30-23:00, PH Fr,SH Fr 11:30-02:00, PH Sa-Su 11:30-22:00", + "Mo-Th 17:00-23:00, SH Mo-Th 14:00-23:00, Fr 14:00-02:00, Sa,Su 11:30-22:00, PH Mo-Th 11:30-23:00, PH Fr,SH Fr 11:30-02:00, PH Sa-Su 11:30-22:00"); T("Sa,Su,PH,Mo"); T2("Tu-Fr 10:00-17:00; Th 10:00-20:00; Sa,Su,PH Mo 11:00-18:00", "Tu-Fr 10:00-17:00; Th 10:00-20:00; Sa,Su,PH,Mo 11:00-18:00"); T2("Mo,We,Th PH off", "PH Mo,We,Th off"); @@ -86,6 +92,7 @@ T("Mar 01-Mar Su[-2] Mo 17:00-18:00; PH off"); T("Oct Su[-1]-Dec 31 08:00-18:00"); T("Oct Su[-1]-Dec 31 Su 08:00-18:00"); + T("Mar Su[1]-Oct Su[1]: 11:00-20:00; PH 11:00-20:00"); // from https://wiki.openstreetmap.org/wiki/Key:opening_hours#Simple_examples T("Mo-Fr 08:00-17:30"); @@ -95,7 +102,7 @@ T("Mo-Fr 08:00-12:00,13:00-17:30; Sa 08:00-12:00; PH 09:00-12:00"); // from https://wiki.openstreetmap.org/wiki/Key:opening_hours#Examples - T("Sa-Su 00:00-24:00"); + T3("Sa-Su 00:00-24:00", nullptr, "Sa,Su 00:00-24:00"); T("Mo-Fr 08:30-20:00"); T("Mo 10:00-12:00,12:30-15:00; Tu-Fr 08:00-12:00,12:30-15:00; Sa 08:00-12:00"); T("Mo-Su 08:00-18:00; Apr 10-15 off; Jun 08:00-14:00; Aug off; Dec 25 off"); @@ -105,14 +112,14 @@ T("Su 10:00+"); T2("week 1-53/2 Fr 09:00-12:00; week 2-52/2 We 09:00-12:00", "week 01-53/2 Fr 09:00-12:00; week 02-52/2 We 09:00-12:00"); T("Mo-Sa 08:00-13:00,14:00-17:00 || \"by appointment\""); - T("Su-Tu 11:00-01:00, We-Th 11:00-03:00, Fr 11:00-06:00, Sa 11:00-07:00"); + T3("Su-Tu 11:00-01:00, We-Th 11:00-03:00, Fr 11:00-06:00, Sa 11:00-07:00", nullptr, "Su-Tu 11:00-01:00, We,Th 11:00-03:00, Fr 11:00-06:00, Sa 11:00-07:00"); T("Mo-Su,PH 15:00-03:00; easter -2 days off"); // from https://openingh.openstreetmap.de/evaluation_tool/ T("Mo-Fr 10:00-20:00; PH off"); T("Mo,Tu,Th,Fr 12:00-18:00; Sa,PH 12:00-17:00; Th[3],Th[-1] off"); T("00:00-24:00; Tu-Su,PH 08:30-09:00 off; Tu-Su 14:00-14:30 off; Mo 08:00-13:00 off"); - T("Fr-Sa 18:00-06:00; PH off"); + T3("Fr-Sa 18:00-06:00; PH off", nullptr, "Fr,Sa 18:00-06:00; PH off"); T("Mo 10:00-12:00,12:30-15:00"); T("Mo 10:00-12:00,12:30-15:00; Tu-Fr 08:00-12:00,12:30-15:00; Sa 08:00-12:00"); T("\"only after registration\"; PH off"); @@ -122,7 +129,7 @@ T("Mo-Su 22:00-23:00; We,PH off"); T("We-Fr 10:00-24:00 open \"it is open\" || \"please call\"; PH off"); T("Mo-Fr 08:00-11:00 || Tu-Th,PH open \"Emergency only\""); - T("Tu-Th,We 22:00-23:00 open \"Hot meals\"; PH off"); + T3("Tu-Th,We 22:00-23:00 open \"Hot meals\"; PH off", nullptr, "Tu-Th 22:00-23:00 open \"Hot meals\"; PH off"); // We redundant T("Mo 12:00-14:00 open \"female only\", Mo 14:00-16:00 open \"male only\"; PH off"); T("Apr: 22:00-23:00; PH off"); T("Jul-Jan: 22:00-23:00; PH off"); @@ -134,7 +141,7 @@ T("Mar Su[-1]-Dec Su[1] -2 days: 22:00-23:00; PH off"); T("Sa[1],Sa[1] +1 day 10:00-12:00 open \"first weekend in the month\"; PH off"); T("Sa[-1],Sa[-1] +1 day 10:00-12:00 open \"last weekend in the month\"; PH off"); - T("Sa-Su 00:00-24:00; PH off"); + T3("Sa-Su 00:00-24:00; PH off", nullptr, "Sa,Su 00:00-24:00; PH off"); T("Mo-Fr 00:00-24:00; PH off"); T("sunrise-sunset open \"Beware of sunburn!\"; PH off"); T("sunset-sunrise open \"Beware of vampires!\"; PH off"); @@ -173,7 +180,8 @@ T("Oct: We[1]"); // from https://github.com/dfaure/DataNovaImportScripts/blob/master/saved_opening_hours - T("Mo-Tu,Th-Fr 09:30-12:00; 2020 Dec 28 off; 2020 Dec 22,2020 Dec 29 off; We 15:00-17:00; 2020 Dec 23,2020 Dec 30 off; 2020 Dec 24,2020 Dec 31 off; Sa 10:00-12:00; 2020 Dec 26,2021 Jan 02 off; PH off"); + T3("Mo-Tu,Th-Fr 09:30-12:00; 2020 Dec 28 off; 2020 Dec 22,2020 Dec 29 off; We 15:00-17:00; 2020 Dec 23,2020 Dec 30 off; 2020 Dec 24,2020 Dec 31 off; Sa 10:00-12:00; 2020 Dec 26,2021 Jan 02 off; PH off", nullptr, + "Mo,Tu,Th,Fr 09:30-12:00; 2020 Dec 28 off; 2020 Dec 22,2020 Dec 29 off; We 15:00-17:00; 2020 Dec 23,2020 Dec 30 off; 2020 Dec 24,2020 Dec 31 off; Sa 10:00-12:00; 2020 Dec 26,2021 Jan 02 off; PH off"); // real-world tests from Osmose that we were handling wrongly T("Tu-Fr 11:30-14:30 open, 14:30-18:00 open \"pickup only\", 18:00-22:00 open"); @@ -181,8 +189,9 @@ T2("Apr-Sep 09:00-19:00; Mar-Oct. 09:00-18:00; Nov.-Feb. 09:00-17:00", "Apr-Sep 09:00-19:00; Mar-Oct 09:00-18:00; Nov-Feb 09:00-17:00"); T2("week 23-37 12:30-15:00,20:00-23:00; week 01-22,38-53 off", "week 23-37 12:30-15:00,20:00-23:00; week 01-22,38-53 off"); T("Mo-Sa 09:00-20:00; Su[-2,-1] 12:30-18:00"); - T("Su off, Sa-Fr 08:30-13:00; Mo-Th 08:30-13:30,16:00-20:00"); - T("Mo-Tu 09:00-12:00,14:00-18:00, We closed, Th-Sa 09:00-12:00,14:00-18:00; Su 09:30-12:30,14:30-18:00"); + T("Su off, Mo-Fr 08:30-13:00; Mo-Th 08:30-13:30,16:00-20:00"); + T3("Mo-Tu 09:00-12:00,14:00-18:00, We closed, Th-Sa 09:00-12:00,14:00-18:00; Su 09:30-12:30,14:30-18:00", nullptr, + "Mo,Tu 09:00-12:00,14:00-18:00, We closed, Th-Sa 09:00-12:00,14:00-18:00; Su 09:30-12:30,14:30-18:00"); T2("SH Sep-Jun Mo 10:52-15:52", "SH, Sep-Jun Mo 10:52-15:52"); // likely incorrect, but at least no information loss // weekday autocorrect @@ -270,15 +279,15 @@ T2("Du lundi au vendredi : 9:00-18:00", "Mo-Fr 09:00-18:00"); // Unicode symbols - T2("Mo???Tu", "Mo-Tu"); + T3("Mo???Tu", "Mo-Tu", "Mo,Tu"); T2("13???41", "13:41"); T2("10???00???19???00", "10:00-19:00"); T2("10???00???17???00", "10:00-17:00"); T2("11:00???23:00", "11:00-23:00"); T2("11:00???15:00", "11:00-15:00"); - T2("We 09:00-18:00\xC2\xA0; Sa-Su 09:00-18:00", "We 09:00-18:00; Sa-Su 09:00-18:00"); // weird space + T2("We 09:00-18:00\xC2\xA0; Sa 09:00-19:00", "We 09:00-18:00; Sa 09:00-19:00"); // weird space T2("LUNDI 08:30?????????17:00", "Mo 08:30-17:00"); - T2("???,???,???,???,??? 11:00-19:00", "Mo,Th,Fr,Sa,Su 11:00-19:00"); + T3("???,???,???,???,??? 11:00-19:00", "Mo,Th,Fr,Sa,Su 11:00-19:00", "Th-Mo 11:00-19:00"); T2("???-??? 09:00-18:00", "Mo-Sa 09:00-18:00"); T2("?????????????????????10:00???19:00", "We-Sa 10:00-19:00"); T2("????????? ???17:00???23:00", "Mo-Sa 17:00-23:00"); @@ -299,40 +308,65 @@ T2("Senin-Sabtu 09:00-16:00, Minggu 09:00-18:00", "Mo-Sa 09:00-16:00, Su 09:00-18:00"); T2("Lundi-samedi 8H00-12H00 16H00-20H00 dimanche,jours f??ri??s 9H00-12H00 17H00-20H00", "Mo-Sa 08:00-12:00,16:00-20:00; Su,PH 09:00-12:00,17:00-20:00"); T2("De f??vrier ?? novembre", "Feb-Nov"); - T2("Ma,Me,Je,Ve 8h-12h30, 14h-19h; Sa 8h-12h30, 14h-18h", "Tu,We,Th,Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:00-18:00"); + T3("Ma,Me,Je,Ve 8h-12h30, 14h-19h; Sa 8h-12h30, 14h-18h", "Tu,We,Th,Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:00-18:00", "Tu-Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:00-18:00"); T2("Mo-Fr: 10:00-18:30 Uhr Sa: 10:00-13:30 Uhr", "Mo-Fr 10:00-18:30; Sa 10:00-13:30"); T2("Montag & Dienstag Ruhetag", "Mo,Tu closed"); // recovery from wrong rule separators - T2("Fr-Sa 10:00-02:00,Su 10:00-20:00", "Fr-Sa 10:00-02:00, Su 10:00-20:00"); + T2("Fr,Sa 10:00-02:00,Su 10:00-20:00", "Fr,Sa 10:00-02:00, Su 10:00-20:00"); T2("tu-sa 12:00-14:30,mo-sa 18:30-22:00", "Tu-Sa 12:00-14:30, Mo-Sa 18:30-22:00"); T2("Mo 07:00-12:00,Tu 15:00-20:00,We 07:00-12:00,Fr 15:00-20:00", "Mo 07:00-12:00, Tu 15:00-20:00, We 07:00-12:00, Fr 15:00-20:00"); T2("Mo-Fr 09:00-17:00 Sa 09:00-14:00", "Mo-Fr 09:00-17:00; Sa 09:00-14:00"); T2("Friday 11AM???2:30AM Saturday 10AM???3:30AM Sunday 9AM???4:30AM", "Fr 11:00-02:30; Sa 10:00-03:30; Su 09:00-04:30"); + T2("Mo-Sa 12:00-15:00; 18:00-24:00", "Mo-Sa 12:00-15:00,18:00-24:00"); + T2("Mo-Sa 12:00-15:00; Mo-Sa 18:00-24:00", "Mo-Sa 12:00-15:00,18:00-24:00"); + T2("Mo 12:00-15:00; Mo 18:00-24:00", "Mo 12:00-15:00,18:00-24:00"); // recovery from wrong time selector separators - T2("Dimanche Ferm?? Lundi 08:00 ??? 12:30 14:00 ??? 19:00 Mardi 08:00 ??? 12:30 14:00 ??? 19:00 Mercredi 08:00 ??? 12:30 14:00 ??? 19:00 Jeudi 08:00 ??? 12:30 14:00 ??? 19:00 Vendredi 08:00 ??? 12:30 14:00 ??? 19:00 Samedi 08:00 ??? 12:30 14:30 ??? 18:00", "Su closed; Mo 08:00-12:30,14:00-19:00; Tu 08:00-12:30,14:00-19:00; We 08:00-12:30,14:00-19:00; Th 08:00-12:30,14:00-19:00; Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:30-18:00"); + T3("Dimanche Ferm?? Lundi 08:00 ??? 12:30 14:00 ??? 19:00 Mardi 08:00 ??? 12:30 14:00 ??? 19:00 Mercredi 08:00 ??? 12:30 14:00 ??? 19:00 Jeudi 08:00 ??? 12:30 14:00 ??? 19:00 Vendredi 08:00 ??? 12:30 14:00 ??? 19:00 Samedi 08:00 ??? 12:30 14:30 ??? 18:00", + "Su closed; Mo 08:00-12:30,14:00-19:00; Tu 08:00-12:30,14:00-19:00; We 08:00-12:30,14:00-19:00; Th 08:00-12:30,14:00-19:00; Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:30-18:00", + "Su closed; Mo-Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:30-18:00"); // recovery from slashes abused as rule or timespan separators T2("09:00-12:00/13:00-19:00", "09:00-12:00,13:00-19:00"); T2("10:00 - 13:30 / 17:00 - 20:30", "10:00-13:30,17:00-20:30"); T2("Mo-Fr 6:00-18:00 / Sa 6:00-13:00 / So 7:00-17:00", "Mo-Fr 06:00-18:00; Sa 06:00-13:00; Su 07:00-17:00"); + + // Simplification of the output + T3("Mo 08:00-13:00; Tu 08:00-13:00", nullptr, "Mo,Tu 08:00-13:00"); + T3("Mo-Th 08:00-13:00; Sa[1],Su[-1] 08:00-13:00", "Mo-Th 08:00-13:00; Sa[1],Su[-1] 08:00-13:00", "Mo-Th,Sa[1],Su[-1] 08:00-13:00"); + T("easter +1 day 08:00-13:00; Tu,Sa,Su 08:00-13:00"); // does not simplify + T3("Mo-Sa 12:00-15:00, Mo-Sa 18:00-24:00", "Mo-Sa 12:00-15:00, Mo-Sa 18:00-24:00", "Mo-Sa 12:00-15:00,18:00-24:00"); + T3("Mo 12:00-15:00, Mo 18:00-24:00", "Mo 12:00-15:00, Mo 18:00-24:00", "Mo 12:00-15:00,18:00-24:00"); + T3("Mo-We,Fr,Su 08:00-13:00", "Mo-We,Fr,Su 08:00-13:00", "Su-We,Fr 08:00-13:00"); + T3("Mo,We,Th,Tu,Sa 08:00-13:00", "Mo,We,Th,Tu,Sa 08:00-13:00", "Mo-Th,Sa 08:00-13:00"); // reordering + T3("Mo-Fr,Tu,We 08:00-13:00", "Mo-Fr,Tu,We 08:00-13:00", "Mo-Fr 08:00-13:00"); // Tu,We already included + T3("Sa-Mo 10:00-23:00, Th 10:00-23:00", "Sa-Mo 10:00-23:00, Th 10:00-23:00", "Sa-Mo,Th 10:00-23:00"); // beginDay > endDay + T3("Sa-Mo 10:00-23:00, Fr 10:00-23:00", "Sa-Mo 10:00-23:00, Fr 10:00-23:00", "Fr-Mo 10:00-23:00"); // beginDay > endDay + T3("Su-Th 10:00-23:00, Fr-Sa 10:00-23:00", "Su-Th 10:00-23:00, Fr-Sa 10:00-23:00", "Mo-Su 10:00-23:00"); // beginDay > endDay #undef T #undef T2 +#undef T3 } void testSuccess() { QFETCH(QByteArray, input); QFETCH(QByteArray, expectedOutput); + QFETCH(QByteArray, expectedSimplifiedOutput); OpeningHours oh(input); QVERIFY(oh.error() != OpeningHours::SyntaxError); QCOMPARE(oh.normalizedExpression(), expectedOutput); + QCOMPARE(oh.simplifiedExpression(), expectedSimplifiedOutput); // verify the expressions we generate are parsed correctly as well OpeningHours oh2(oh.normalizedExpression()); - QVERIFY(oh.error() != OpeningHours::SyntaxError); + QVERIFY(oh2.error() != OpeningHours::SyntaxError); QCOMPARE(oh2.normalizedExpression(), oh.normalizedExpression()); + + OpeningHours oh3(oh.simplifiedExpression()); + QVERIFY(oh3.error() != OpeningHours::SyntaxError); + QCOMPARE(oh3.normalizedExpression(), oh.simplifiedExpression()); } void testFail_data() @@ -423,6 +457,8 @@ OpeningHours oh(expression); QCOMPARE(oh.error(), error); + (void)oh.normalizedExpression(); // don't crash + (void)oh.simplifiedExpression(); // don't crash } }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/po/eu/kopeninghours.po new/kopeninghours-21.08.0/po/eu/kopeninghours.po --- old/kopeninghours-21.04.3/po/eu/kopeninghours.po 1970-01-01 01:00:00.000000000 +0100 +++ new/kopeninghours-21.08.0/po/eu/kopeninghours.po 2021-08-06 02:26:26.000000000 +0200 @@ -0,0 +1,145 @@ +# Translation for kopeninghours.po to Euskara/Basque (eu). +# Copyright (C) 2021, This file is copyright: +# This file is distributed under the same license as the kopeninghours package. +# KDE euskaratzeko proiektuko arduraduna <[email protected]>. +# +# Translators: +# I??igo Salvador Azurmendi <[email protected]>, 2021. +msgid "" +msgstr "" +"Project-Id-Version: kopeninghours\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2020-12-23 02:25+0100\n" +"PO-Revision-Date: 2021-08-03 23:07+0200\n" +"Last-Translator: I??igo Salvador Azurmendi <[email protected]>\n" +"Language-Team: Basque <[email protected]>\n" +"Language: eu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 21.04.3\n" + +#: lib/display.cpp:28 +#, kde-format +msgid "Open" +msgstr "Zabalik" + +#: lib/display.cpp:28 +#, kde-format +msgid "Open (%1)" +msgstr "Zabalik (%1)" + +#: lib/display.cpp:30 +#, kde-format +msgid "Closed" +msgstr "Itxita" + +#: lib/display.cpp:30 +#, kde-format +msgid "Closed (%1)" +msgstr "Itxita (%1)" + +#: lib/display.cpp:50 +#, kde-format +msgid "Open for one more minute" +msgid_plural "Open for %1 more minutes" +msgstr[0] "Beste minutu batez zabalik" +msgstr[1] "Beste %1 minutuz zabalik" + +#: lib/display.cpp:51 +#, kde-format +msgid "Open for one more minute (%2)" +msgid_plural "Open for %1 more minutes (%2)" +msgstr[0] "Beste minutu batez zabalik (%2)" +msgstr[1] "Beste %1 minutuz zabalik (%2)" + +#: lib/display.cpp:54 +#, kde-format +msgid "Currently closed, opens in one minute" +msgid_plural "Currently closed, opens in %1 minutes" +msgstr[0] "Une honetan itxita, minutu bat barru zabaltzen du" +msgstr[1] "Une honetan itxita, %1 minutu barru zabaltzen du" + +#: lib/display.cpp:55 +#, kde-format +msgid "Currently closed (%2), opens in one minute" +msgid_plural "Currently closed (%2), opens in %1 minutes" +msgstr[0] "Une honetan itxita (%2), minutu bat barru zabaltzen du" +msgstr[1] "Une honetan itxita (%2), %1 minutu barru zabaltzen du" + +#: lib/display.cpp:68 +#, kde-format +msgid "Open for one more hour" +msgid_plural "Open for %1 more hours" +msgstr[0] "Beste ordu betez zabalik" +msgstr[1] "Beste %1 orduz zabalik" + +#: lib/display.cpp:69 +#, kde-format +msgid "Open for one more hour (%2)" +msgid_plural "Open for %1 more hours (%2)" +msgstr[0] "Beste ordu betez zabalik (%2)" +msgstr[1] "Beste %1 orduz zabalik (%2)" + +#: lib/display.cpp:72 +#, kde-format +msgid "Currently closed, opens in one hour" +msgid_plural "Currently closed, opens in %1 hours" +msgstr[0] "Une honetan itxita, ordubete barru zabaltzen du" +msgstr[1] "Une honetan itxita, %1 ordu barru zabaltzen du" + +#: lib/display.cpp:73 +#, kde-format +msgid "Currently closed (%2), opens in one hour" +msgid_plural "Currently closed (%2), opens in %1 hours" +msgstr[0] "Une honetan itxita (%2), ordubete barru zabaltzen du" +msgstr[1] "Une honetan itxita (%2), %1 ordu barru zabaltzen du" + +#: lib/display.cpp:86 +#, kde-format +msgid "Open for one more day" +msgid_plural "Open for %1 more days" +msgstr[0] "Beste egun batez zabalik" +msgstr[1] "Beste %1 egunez zabalik" + +#: lib/display.cpp:87 +#, kde-format +msgid "Open for one more day (%2)" +msgid_plural "Open for %1 more days (%2)" +msgstr[0] "Beste egun batez zabalik (%2)" +msgstr[1] "Beste %1 egunez zabalik (%2)" + +#: lib/display.cpp:90 +#, kde-format +msgid "Currently closed, opens in one day" +msgid_plural "Currently closed, opens in %1 days" +msgstr[0] "Une honetan itxita, egun bat barru zabaltzen du" +msgstr[1] "Une honetan itxita, %1 egun barru zabaltzen du" + +#: lib/display.cpp:91 +#, kde-format +msgid "Currently closed (%2), opens in one day" +msgid_plural "Currently closed (%2), opens in %1 days" +msgstr[0] "Une honetan itxita (%2), egun bat barru zabaltzen du" +msgstr[1] "Une honetan itxita (%2), %1 egun barru zabaltzen du" + +#: lib/display.cpp:102 +#, kde-format +msgid "Currently open" +msgstr "Une honetan zabalik" + +#: lib/display.cpp:102 +#, kde-format +msgid "Currently open (%1)" +msgstr "Une honetan zabalik (%1)" + +#: lib/display.cpp:104 +#, kde-format +msgid "Currently closed" +msgstr "Une honetan itxita" + +#: lib/display.cpp:104 +#, kde-format +msgid "Currently closed (%1)" +msgstr "Une honetan itxita (%1)" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/po/hi/kopeninghours.po new/kopeninghours-21.08.0/po/hi/kopeninghours.po --- old/kopeninghours-21.04.3/po/hi/kopeninghours.po 2021-07-06 07:30:38.000000000 +0200 +++ new/kopeninghours-21.08.0/po/hi/kopeninghours.po 2021-08-06 02:26:26.000000000 +0200 @@ -1,13 +1,14 @@ # Copyright (C) YEAR This file is copyright: # This file is distributed under the same license as the kopeninghours package. # +# Sameer Singh <[email protected]>, 2021. # Raghavendra Kamath <[email protected]>, 2021. msgid "" msgstr "" "Project-Id-Version: kopeninghours\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n" "POT-Creation-Date: 2020-12-23 02:25+0100\n" -"PO-Revision-Date: 2021-06-29 18:31+0530\n" +"PO-Revision-Date: 2021-06-27 14:45+0530\n" "Last-Translator: Raghavendra Kamath <[email protected]>\n" "Language-Team: kde-hindi\n" "Language: hi\n" @@ -30,26 +31,26 @@ #: lib/display.cpp:30 #, kde-format msgid "Closed" -msgstr "????????????" +msgstr "???????????? ??????" #: lib/display.cpp:30 #, kde-format msgid "Closed (%1)" -msgstr "(%1) ????????????" +msgstr "(%1) ???????????? ??????" #: lib/display.cpp:50 #, kde-format msgid "Open for one more minute" msgid_plural "Open for %1 more minutes" -msgstr[0] "?????? ???????????? ?????? ????????? ???????????? ??????" -msgstr[1] "%1 ?????????????????? ?????? ????????? ???????????? ??????" +msgstr[0] "?????? ?????? ???????????? ?????? ????????? ???????????? ??????" +msgstr[1] "%1 ?????? ?????????????????? ?????? ????????? ???????????? ??????" #: lib/display.cpp:51 #, kde-format msgid "Open for one more minute (%2)" msgid_plural "Open for %1 more minutes (%2)" -msgstr[0] "?????? ???????????? ?????? ????????? ???????????? ?????? (%2)" -msgstr[1] "%1 ?????????????????? ?????? ????????? ???????????? ?????? (%2)" +msgstr[0] "?????? ?????? ???????????? ?????? ????????? ???????????? ?????? (%2)" +msgstr[1] "%1 ?????? ?????????????????? ?????? ????????? ???????????? ?????? (%2)" #: lib/display.cpp:54 #, kde-format diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/po/zh_CN/kopeninghours.po new/kopeninghours-21.08.0/po/zh_CN/kopeninghours.po --- old/kopeninghours-21.04.3/po/zh_CN/kopeninghours.po 2021-07-06 07:30:38.000000000 +0200 +++ new/kopeninghours-21.08.0/po/zh_CN/kopeninghours.po 2021-08-06 02:26:27.000000000 +0200 @@ -3,7 +3,7 @@ "Project-Id-Version: kdeorg\n" "Report-Msgid-Bugs-To: https://bugs.kde.org\n" "POT-Creation-Date: 2020-12-23 02:25+0100\n" -"PO-Revision-Date: 2021-06-20 07:38\n" +"PO-Revision-Date: 2021-07-26 13:50\n" "Last-Translator: \n" "Language-Team: Chinese Simplified\n" "Language: zh_CN\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/src/lib/openinghours.cpp new/kopeninghours-21.08.0/src/lib/openinghours.cpp --- old/kopeninghours-21.04.3/src/lib/openinghours.cpp 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/src/lib/openinghours.cpp 2021-08-04 23:42:48.000000000 +0200 @@ -12,6 +12,7 @@ #include "interval.h" #include "rule_p.h" #include "logging.h" +#include "consecutiveaccumulator_p.h" #include <QDateTime> #include <QJsonArray> @@ -52,48 +53,130 @@ auto rule = (*it).get(); auto prevRule = (*(std::prev(it))).get(); - if (rule->m_ruleType != Rule::AdditionalRule || rule->hasComment() || prevRule->hasComment() || !prevRule->hasImplicitState()) { + if (rule->hasComment() || prevRule->hasComment() || !prevRule->hasImplicitState()) { continue; } - const auto prevRuleSingleSelector = prevRule->selectorCount() == 1; const auto curRuleSingleSelector = rule->selectorCount() == 1; - // the previous rule has no time selector, the current rule only has a weekday selector - // so we fold the two rules together - if (!prevRule->m_timeSelector && prevRule->m_weekdaySelector && rule->m_weekdaySelector && !rule->hasWideRangeSelector()) { - auto tmp = std::move(rule->m_weekdaySelector); - rule->m_weekdaySelector = std::move(prevRule->m_weekdaySelector); - rule->m_weekSelector = std::move(prevRule->m_weekSelector); - rule->m_monthdaySelector = std::move(prevRule->m_monthdaySelector); - rule->m_yearSelector = std::move(prevRule->m_yearSelector); - rule->m_colonAfterWideRangeSelector = prevRule->m_colonAfterWideRangeSelector; - auto *selector = rule->m_weekdaySelector.get(); - while (selector->rhsAndSelector) - selector = selector->rhsAndSelector.get(); - appendSelector(selector, std::move(tmp)); - rule->m_ruleType = prevRule->m_ruleType; - std::swap(*it, *std::prev(it)); - it = std::prev(m_rules.erase(it)); - } - - // the current rule only has a time selector, so we append that to the previous rule - else if (curRuleSingleSelector && rule->m_timeSelector && prevRule->m_timeSelector) { - appendSelector(prevRule->m_timeSelector.get(), std::move(rule->m_timeSelector)); - it = std::prev(m_rules.erase(it)); - } - - // previous is a single monthday selector - else if (rule->m_monthdaySelector && prevRuleSingleSelector && prevRule->m_monthdaySelector && !isWiderThan(prevRule, rule)) { - auto tmp = std::move(rule->m_monthdaySelector); - rule->m_monthdaySelector = std::move(prevRule->m_monthdaySelector); - appendSelector(rule->m_monthdaySelector.get(), std::move(tmp)); - rule->m_ruleType = prevRule->m_ruleType; - std::swap(*it, *std::prev(it)); - it = std::prev(m_rules.erase(it)); + if (rule->m_ruleType == Rule::AdditionalRule) { + // the previous rule has no time selector, the current rule only has a weekday selector + // so we fold the two rules together + if (!prevRule->m_timeSelector && prevRule->m_weekdaySelector && rule->m_weekdaySelector && !rule->hasWideRangeSelector()) { + auto tmp = std::move(rule->m_weekdaySelector); + rule->m_weekdaySelector = std::move(prevRule->m_weekdaySelector); + rule->m_weekSelector = std::move(prevRule->m_weekSelector); + rule->m_monthdaySelector = std::move(prevRule->m_monthdaySelector); + rule->m_yearSelector = std::move(prevRule->m_yearSelector); + rule->m_colonAfterWideRangeSelector = prevRule->m_colonAfterWideRangeSelector; + auto *selector = rule->m_weekdaySelector.get(); + while (selector->rhsAndSelector) + selector = selector->rhsAndSelector.get(); + appendSelector(selector, std::move(tmp)); + rule->m_ruleType = prevRule->m_ruleType; + std::swap(*it, *std::prev(it)); + it = std::prev(m_rules.erase(it)); + } + + // the current rule only has a time selector, so we append that to the previous rule + else if (curRuleSingleSelector && rule->m_timeSelector && prevRule->m_timeSelector) { + appendSelector(prevRule->m_timeSelector.get(), std::move(rule->m_timeSelector)); + it = std::prev(m_rules.erase(it)); + } + + // previous is a single monthday selector + else if (rule->m_monthdaySelector && prevRuleSingleSelector && prevRule->m_monthdaySelector && !isWiderThan(prevRule, rule)) { + auto tmp = std::move(rule->m_monthdaySelector); + rule->m_monthdaySelector = std::move(prevRule->m_monthdaySelector); + appendSelector(rule->m_monthdaySelector.get(), std::move(tmp)); + rule->m_ruleType = prevRule->m_ruleType; + std::swap(*it, *std::prev(it)); + it = std::prev(m_rules.erase(it)); + } + } else if (rule->m_ruleType == Rule::NormalRule) { + // Previous rule has time and other selectors + // Current rule is only a time selector + // "Mo-Sa 12:00-15:00; 18:00-24:00" => "Mo-Sa 12:00-15:00,18:00-24:00" + if (curRuleSingleSelector && rule->m_timeSelector + && prevRule->selectorCount() > 1 && prevRule->m_timeSelector) { + appendSelector(prevRule->m_timeSelector.get(), std::move(rule->m_timeSelector)); + it = std::prev(m_rules.erase(it)); + } + + // Both rules have exactly the same selector apart from time + // Ex: "Mo-Sa 12:00-15:00; Mo-Sa 18:00-24:00" => "Mo-Sa 12:00-15:00,18:00-24:00" + // Obviously a bug, it was overwriting the 12:00-15:00 range. + // For now this only supports weekday selectors, could be extended + else if (rule->selectorCount() == prevRule->selectorCount() + && rule->m_timeSelector && prevRule->m_timeSelector + && !rule->hasComment() && !prevRule->hasComment() + && rule->selectorCount() == 2 && rule->m_weekdaySelector && prevRule->m_weekdaySelector + // slower than writing an operator==, but so much easier to write :) + && rule->m_weekdaySelector->toExpression() == prevRule->m_weekdaySelector->toExpression() + ) { + appendSelector(prevRule->m_timeSelector.get(), std::move(rule->m_timeSelector)); + it = std::prev(m_rules.erase(it)); + } + } + } +} + +void OpeningHoursPrivate::simplify() +{ + if (m_error == OpeningHours::SyntaxError || m_rules.empty()) { + return; + } + + for (auto it = std::next(m_rules.begin()); it != m_rules.end(); ++it) { + auto rule = (*it).get(); + auto prevRule = (*(std::prev(it))).get(); + + if (rule->m_ruleType == Rule::AdditionalRule || rule->m_ruleType == Rule::NormalRule) { + + auto hasNoHoliday = [](WeekdayRange *selector) { + return selector->holiday == WeekdayRange::NoHoliday + && !selector->lhsAndSelector; + }; + // Both rules have the same time and a different weekday selector + // Mo 08:00-13:00; Tu 08:00-13:00 => Mo,Tu 08:00-13:00 + if (rule->selectorCount() == prevRule->selectorCount() + && rule->m_timeSelector && prevRule->m_timeSelector + && rule->selectorCount() == 2 && rule->m_weekdaySelector && prevRule->m_weekdaySelector + && hasNoHoliday(rule->m_weekdaySelector.get()) + && hasNoHoliday(prevRule->m_weekdaySelector.get()) + && *rule->m_timeSelector == *prevRule->m_timeSelector + ) { + // We could of course also turn Mo,Tu,We,Th into Mo-Th... + appendSelector(prevRule->m_weekdaySelector.get(), std::move(rule->m_weekdaySelector)); + it = std::prev(m_rules.erase(it)); + continue; + } + } + + if (rule->m_ruleType == Rule::AdditionalRule) { + // Both rules have exactly the same selector apart from time + // Ex: "Mo 12:00-15:00, Mo 18:00-24:00" => "Mo 12:00-15:00,18:00-24:00" + // For now this only supports weekday selectors, could be extended + if (rule->selectorCount() == prevRule->selectorCount() + && rule->m_timeSelector && prevRule->m_timeSelector + && !rule->hasComment() && !prevRule->hasComment() + && rule->selectorCount() == 2 && rule->m_weekdaySelector && prevRule->m_weekdaySelector + // slower than writing an operator==, but so much easier to write :) + && rule->m_weekdaySelector->toExpression() == prevRule->m_weekdaySelector->toExpression() + ) { + appendSelector(prevRule->m_timeSelector.get(), std::move(rule->m_timeSelector)); + it = std::prev(m_rules.erase(it)); + } } } + // Now try collapsing adjacent week days: Mo,Tu,We => Mo-We + for (auto it = m_rules.begin(); it != m_rules.end(); ++it) { + auto rule = (*it).get(); + if (rule->m_weekdaySelector) { + rule->m_weekdaySelector->simplify(); + } + } } void OpeningHoursPrivate::validate() @@ -326,6 +409,12 @@ return ret; } +QByteArray OpeningHours::simplifiedExpression() const +{ + d->simplify(); + return normalizedExpression(); +} + QString OpeningHours::normalizedExpressionString() const { return QString::fromUtf8(normalizedExpression()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/src/lib/openinghours.h new/kopeninghours-21.08.0/src/lib/openinghours.h --- old/kopeninghours-21.04.3/src/lib/openinghours.h 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/src/lib/openinghours.h 2021-08-04 23:42:48.000000000 +0200 @@ -92,6 +92,12 @@ */ QByteArray normalizedExpression() const; + /** Returns a simplified OSM opening hours expression reconstructed from this object. + * In many cases it will be the same as normalizedExpression(), but further + * simplifications can happen, to make the expression shorter/simpler. + */ + QByteArray simplifiedExpression() const; + /** Geographic coordinate at which this expression should be evaluated. * This is needed for expressions containing location-based variable time references, * such as "sunset". If the expression requires a location, error() returns @c MissingLocation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/src/lib/openinghours_p.h new/kopeninghours-21.08.0/src/lib/openinghours_p.h --- old/kopeninghours-21.04.3/src/lib/openinghours_p.h 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/src/lib/openinghours_p.h 2021-08-04 23:42:48.000000000 +0200 @@ -26,6 +26,7 @@ public: void finalizeRecovery(); void autocorrect(); + void simplify(); void validate(); void addRule(Rule *parsedRule); void restartFrom(int pos, Rule::Type nextRuleType); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/src/lib/openinghourslexer.l new/kopeninghours-21.08.0/src/lib/openinghourslexer.l --- old/kopeninghours-21.04.3/src/lib/openinghourslexer.l 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/src/lib/openinghourslexer.l 2021-08-04 23:42:48.000000000 +0200 @@ -71,6 +71,7 @@ " days" { return T_KEYWORD_DAY; } "week" { return T_KEYWORD_WEEK; } "easter" { return T_EASTER; } +"whitsun" { return T_WHITSUN; } // non-standard, will be turned into "easter +49 days" /* am/pm time format support, non-standard and has to appear before the generic number token. */ [0-5]?[0-9](\ ?a\.?m\.?|a) { yylval->num = std::strtol(yytext, nullptr, 10); return T_ALT_TIME_AM; } @@ -98,6 +99,14 @@ Sat? { yylval->num = 6; return T_WEEKDAY; } Sun? { yylval->num = 7; return T_WEEKDAY; } +Mo\. { yylval->num = 1; return T_WEEKDAY; } +Tu\. { yylval->num = 2; return T_WEEKDAY; } +We\. { yylval->num = 3; return T_WEEKDAY; } +Th\. { yylval->num = 4; return T_WEEKDAY; } +Fr\. { yylval->num = 5; return T_WEEKDAY; } +Sa\. { yylval->num = 6; return T_WEEKDAY; } +Su\. { yylval->num = 7; return T_WEEKDAY; } + /* same for month names, technically those should be three letter English abbreviations */ "January" { yylval->num = 1; return T_MONTH; } "February" { yylval->num = 2; return T_MONTH; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/src/lib/openinghoursparser.y new/kopeninghours-21.08.0/src/lib/openinghoursparser.y --- old/kopeninghours-21.04.3/src/lib/openinghoursparser.y 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/src/lib/openinghoursparser.y 2021-08-04 23:42:48.000000000 +0200 @@ -158,6 +158,7 @@ %token T_KEYWORD_WEEK %token T_EASTER +%token T_WHITSUN %token <num> T_WEEKDAY %token <num> T_MONTH @@ -667,7 +668,7 @@ | DateFrom[D] DateOffset[O] { $$ = new MonthdayRange; $$->begin = $D; - $$->begin.offset = $O; + $$->begin.offset += $O; $$->end = $$->begin; } | DateFrom[F] RangeSeparator DateTo[T] { @@ -680,7 +681,7 @@ | DateFrom[F] DateOffset[OF] RangeSeparator DateTo[T] { $$ = new MonthdayRange; $$->begin = $F; - $$->begin.offset = $OF; + $$->begin.offset += $OF; $$->end = $T; if ($$->end.year == 0) { $$->end.year = $$->begin.year; } if ($$->end.month == 0) { $$->end.month = $$->begin.month; } @@ -691,7 +692,7 @@ $$->end = $T; if ($$->end.year == 0) { $$->end.year = $$->begin.year; } if ($$->end.month == 0) { $$->end.month = $$->begin.month; } - $$->end.offset = $OT; + $$->end.offset += $OT; } | DateFrom[F] RangeSeparator T_MONTH[M] AltMonthdayOffset[O] { $$ = new MonthdayRange; @@ -706,11 +707,11 @@ | DateFrom[F] DateOffset[OF] RangeSeparator DateTo[T] DateOffset[OT] { $$ = new MonthdayRange; $$->begin = $F; - $$->begin.offset = $OF; + $$->begin.offset += $OF; $$->end = $T; if ($$->end.year == 0) { $$->end.year = $$->begin.year; } if ($$->end.month == 0) { $$->end.month = $$->begin.month; } - $$->end.offset = $OT; + $$->end.offset += $OT; } ; @@ -737,6 +738,7 @@ VariableDate: T_EASTER { $$ = { 0, 0, 0, Date::Easter, { 0, 0, 0 } }; } +| T_WHITSUN { $$ = { 0, 0, 0, Date::Easter, { 49, 0, 0 } }; } ; AltMonthdayOffset: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/src/lib/selectors.cpp new/kopeninghours-21.08.0/src/lib/selectors.cpp --- old/kopeninghours-21.04.3/src/lib/selectors.cpp 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/src/lib/selectors.cpp 2021-08-04 23:42:48.000000000 +0200 @@ -133,6 +133,16 @@ return expr; } +bool Timespan::operator==(Timespan &other) const +{ + return begin == other.begin && + end == other.end && + openEnd == other.openEnd && + interval == other.interval && + bool(next) == (bool)other.next && + (!next || *next == *other.next); +} + int WeekdayRange::requiredCapabilities() const { // only ranges or nthMask are allowed, not both at the same time, enforced by parser @@ -211,6 +221,104 @@ return expr; } +void WeekdayRange::simplify() +{ + QMap<int, WeekdayRange *> endToSelectorMap; + bool seenDays[8]; + const int endIdx = sizeof(seenDays); + std::fill(std::begin(seenDays), std::end(seenDays), false); + for (WeekdayRange *selector = this; selector; selector = selector->next.get()) { + // Ensure it's all just week days, no other features + if (selector->nthMask || selector->lhsAndSelector || selector->holiday != NoHoliday || selector->offset) { + return; + } + const bool wrap = selector->beginDay > selector->endDay; + for (int day = selector->beginDay; day <= selector->endDay + (wrap ? 7 : 0); ++day) { + seenDays[(day - 1) % 7 + 1] = true; + } + endToSelectorMap.insert(selector->endDay, selector); + } + + QString str; + for (int idx = 1; idx < endIdx; ++idx) { + str += QLatin1Char(seenDays[idx] ? '1' : '0'); + } + + // Clear everything and refill + next.reset(nullptr); + + int startIdx = 1; + + // -1 and +1 in a wrapping world + auto prevIdx = [&](int idx) { + Q_ASSERT(idx > 0 && idx < 8); + return idx == 1 ? 7 : (idx - 1); + }; + auto nextIdx = [&](int idx) { + Q_ASSERT(idx > 0 && idx < 8); + return idx % 7 + 1; + }; + + // like std::find, but let's use indexes - and wrap at 8 + auto find = [&](int idx, bool value) { + do { + if (seenDays[idx] == value) + return idx; + idx = nextIdx(idx); + } while(idx != startIdx); + return idx; + }; + auto findPrev = [&](int idx, bool value) { + for (; idx > 0; --idx) { + if (seenDays[idx] == value) + return idx; + } + return 0; + }; + + WeekdayRange *prev = nullptr; + WeekdayRange *selector = this; + + auto addRange = [&](int from, int to) { + if (prev) { + selector = new WeekdayRange; + prev->next.reset(selector); + } + selector->beginDay = from; + selector->endDay = to; + prev = selector; + + }; + + int idx = 0; + if (seenDays[1]) { + // monday is set, try going further back + idx = findPrev(7, false); + if (idx) { + idx = nextIdx(idx); + } + } + if (idx == 0) { + // start at first day being set (Tu or more) + idx = find(1, true); + } + startIdx = idx; + Q_ASSERT(startIdx > 0); + do { + // find end of 'true' range + const int finishIdx = find(idx, false); + // if the range is only 2 items, prefer Mo,Tu over Mo-Tu + if (finishIdx == nextIdx(nextIdx(idx))) { + addRange(idx, idx); + const int n = nextIdx(idx); + addRange(n, n); + } else { + addRange(idx, prevIdx(finishIdx)); + } + idx = find(finishIdx, true); + } while (idx != startIdx); +} + int Week::requiredCapabilities() const { if (endWeek < beginWeek) { // is this even officially allowed? @@ -286,6 +394,18 @@ return weekday == other.weekday && nthWeekday == other.nthWeekday && dayOffset == other.dayOffset; } +DateOffset &DateOffset::operator+=(DateOffset other) +{ + // Only dayOffset really supports += (this is for whitsun) + dayOffset += other.dayOffset; + // The others can't possibly be set already + Q_ASSERT(weekday == 0); + Q_ASSERT(nthWeekday == 0); + weekday = other.weekday; + nthWeekday = other.nthWeekday; + return *this; +} + bool Date::operator==(Date other) const { if (variableDate != other.variableDate) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/src/lib/selectors_p.h new/kopeninghours-21.08.0/src/lib/selectors_p.h --- old/kopeninghours-21.04.3/src/lib/selectors_p.h 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/src/lib/selectors_p.h 2021-08-04 23:42:48.000000000 +0200 @@ -124,6 +124,7 @@ bool isMultiDay(QDate date, OpeningHoursPrivate *context) const; SelectorResult nextInterval(const Interval &interval, const QDateTime &dt, OpeningHoursPrivate *context) const; QByteArray toExpression() const; + bool operator==(Timespan &other) const; Time begin = { Time::NoEvent, -1, -1 }; Time end = { Time::NoEvent, -1, -1 }; @@ -140,8 +141,9 @@ SelectorResult nextInterval(const Interval &interval, const QDateTime &dt, OpeningHoursPrivate *context) const; SelectorResult nextIntervalLocal(const Interval &interval, const QDateTime &dt, OpeningHoursPrivate *context) const; QByteArray toExpression() const; + void simplify(); - uint8_t beginDay = 0; + uint8_t beginDay = 0; // Mo=1, Tu=2, ..., Su=7 uint8_t endDay = 0; uint16_t nthMask = 0; int16_t offset = 0; @@ -175,6 +177,7 @@ { public: bool operator==(DateOffset other) const; + DateOffset &operator+=(DateOffset other); int16_t dayOffset; int8_t weekday; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/src/qml/kopeninghoursqmlplugin.cpp new/kopeninghours-21.08.0/src/qml/kopeninghoursqmlplugin.cpp --- old/kopeninghours-21.04.3/src/qml/kopeninghoursqmlplugin.cpp 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/src/qml/kopeninghoursqmlplugin.cpp 2021-08-04 23:42:48.000000000 +0200 @@ -9,6 +9,7 @@ #include <KOpeningHours/IntervalModel> #include <KOpeningHours/OpeningHours> +#include <QCoreApplication> #include <QQmlContext> #include <QQmlEngine> #include <QQmlExtensionPlugin> @@ -47,9 +48,12 @@ qmlRegisterType<KOpeningHours::IntervalModel>("org.kde.kopeninghours", 1, 0, "IntervalModel"); - qmlRegisterSingletonType("org.kde.kopeninghours", 1, 0, "OpeningHoursParser", [](QQmlEngine*, QJSEngine *engine) -> QJSValue { - return engine->toScriptValue(KOpeningHours::OpeningHoursFactory()); - }); + // HACK qmlplugindump chokes on gadget singletons, to the point of breaking ecm_find_qmlmodule() + if (QCoreApplication::applicationName() != QLatin1String("qmlplugindump")) { + qmlRegisterSingletonType("org.kde.kopeninghours", 1, 0, "OpeningHoursParser", [](QQmlEngine*, QJSEngine *engine) -> QJSValue { + return engine->toScriptValue(KOpeningHours::OpeningHoursFactory()); + }); + } } #include "kopeninghoursqmlplugin.moc" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kopeninghours-21.04.3/tests/osm-opening-hours-validate.cpp new/kopeninghours-21.08.0/tests/osm-opening-hours-validate.cpp --- old/kopeninghours-21.04.3/tests/osm-opening-hours-validate.cpp 2021-07-05 20:56:43.000000000 +0200 +++ new/kopeninghours-21.08.0/tests/osm-opening-hours-validate.cpp 2021-08-04 23:42:48.000000000 +0200 @@ -34,6 +34,7 @@ in.open(stdin, QFile::ReadOnly); int total = 0; int normalized = 0; + int simplified = 0; int errors = 0; char line[4096]; while (!in.atEnd()) { @@ -59,10 +60,18 @@ ++normalized; std::cerr << "Expression " << QByteArray(line, size).constData() << " normalized to " << n.constData() << std::endl; } + const auto simplifiedExpr = oh.simplifiedExpression(); + if (n != simplifiedExpr) { + ++simplified; + std::cerr << "Expression " << n.constData() << " simplified to " << simplifiedExpr.constData() << std::endl; + } } } - std::cerr << total << " expressions checked, " << errors << " invalid, " << normalized << " not in normal form" << std::endl; + std::cerr << total << " expressions checked, " + << errors << " invalid, " + << normalized << " not in normal form, " + << simplified << " can be simplified" << std::endl; return errors; } else { OpeningHours oh(parser.positionalArguments().at(0).toUtf8());
