diff --git a/CHANGELOG.md b/CHANGELOG.md index 06bda83ec..3d817bd0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - FIXED: Use smaller range for U-turn angles in map-matching [#4920](https://github.com/Project-OSRM/osrm-backend/pull/4920) - FIXED: Remove the last short annotation segment in `trimShortSegments` [#4946](https://github.com/Project-OSRM/osrm-backend/pull/4946) - FIXED: Properly calculate annotations for speeds, durations and distances when waypoints are used with mapmatching [#4949](https://github.com/Project-OSRM/osrm-backend/pull/4949) + - FIXED: Don't apply unimplemented SH and PH conditions in OpeningHours and add inversed date ranges [#4992](https://github.com/Project-OSRM/osrm-backend/issues/4992) - Profile: - CHANGED: Handle oneways in get_forward_backward_by_key [#4929](https://github.com/Project-OSRM/osrm-backend/pull/4929) - FIXED: Do not route against oneway road if there is a cycleway in the wrong direction; also review bike profile [#4943](https://github.com/Project-OSRM/osrm-backend/issues/4943) diff --git a/include/util/opening_hours.hpp b/include/util/opening_hours.hpp index 658ee9517..63b82c453 100644 --- a/include/util/opening_hours.hpp +++ b/include/util/opening_hours.hpp @@ -166,12 +166,18 @@ struct OpeningHours date_to = date_from; } + const bool inverse = (from.year == 0) && (to.year == 0) && (date_from > date_to); + if (inverse) + { + std::swap(date_from, date_to); + } + if (!use_curr_day) date_from += date_duration(1); if (use_next_day && date_to != date(boost::gregorian::max_date_time)) date_to += date_duration(1); - return date_from <= date_current && date_current <= date_to; + return (date_from <= date_current && date_current <= date_to) ^ inverse; } }; @@ -181,29 +187,30 @@ struct OpeningHours { bool use_curr_day = true; // the first matching time uses the current day bool use_next_day = false; // the first matching time uses the next day - return - // the value is in range if time is not specified or is in any time range - // (also modifies use_curr_day and use_next_day flags to handle overnight day ranges, - // e.g. for 22:00-03:00 and 2am -> use_curr_day = false and use_next_day = true) - (times.empty() || std::any_of(times.begin(), - times.end(), - [&time, &use_curr_day, &use_next_day](const auto &x) { - return x.IsInRange(time, use_curr_day, use_next_day); - })) - // .. and if weekdays are not specified or matches weekdays range - && (weekdays.empty() || - std::any_of(weekdays.begin(), - weekdays.end(), - [&time, use_curr_day, use_next_day](const auto &x) { - return x.IsInRange(time, use_curr_day, use_next_day); - })) - // .. and if month-day ranges are not specified or is in any month-day range - && (monthdays.empty() || - std::any_of(monthdays.begin(), - monthdays.end(), - [&time, use_curr_day, use_next_day](const auto &x) { - return x.IsInRange(time, use_curr_day, use_next_day); - })); + return (!times.empty() || !weekdays.empty() || !monthdays.empty()) + // the value is in range if time is not specified or is in any time range + // (also modifies use_curr_day and use_next_day flags to handle overnight day ranges, + // e.g. for 22:00-03:00 and 2am -> use_curr_day = false and use_next_day = true) + && (times.empty() || + std::any_of(times.begin(), + times.end(), + [&time, &use_curr_day, &use_next_day](const auto &x) { + return x.IsInRange(time, use_curr_day, use_next_day); + })) + // .. and if weekdays are not specified or matches weekdays range + && (weekdays.empty() || + std::any_of(weekdays.begin(), + weekdays.end(), + [&time, use_curr_day, use_next_day](const auto &x) { + return x.IsInRange(time, use_curr_day, use_next_day); + })) + // .. and if month-day ranges are not specified or is in any month-day range + && (monthdays.empty() || + std::any_of(monthdays.begin(), + monthdays.end(), + [&time, use_curr_day, use_next_day](const auto &x) { + return x.IsInRange(time, use_curr_day, use_next_day); + })); } std::vector times; diff --git a/src/util/opening_hours.cpp b/src/util/opening_hours.cpp index 6436b90fc..6d74c854e 100644 --- a/src/util/opening_hours.cpp +++ b/src/util/opening_hours.cpp @@ -303,7 +303,7 @@ struct opening_hours_grammar : qi::grammar> (&~lit(':') | eoi) + >> !qi::no_skip[lit(':') >> uint2_p] // distinguish "daynum:.." from "hour:minute" ; weeknum = uint2_p[_pass = bind([](unsigned x) { return 01 <= x && x <= 53; }, _1), _val = _1]; diff --git a/unit_tests/util/opening_hours_parsing.cpp b/unit_tests/util/opening_hours_parsing.cpp index d6eef920f..d2ace13d5 100644 --- a/unit_tests/util/opening_hours_parsing.cpp +++ b/unit_tests/util/opening_hours_parsing.cpp @@ -49,8 +49,10 @@ BOOST_AUTO_TEST_CASE(check_opening_hours_grammar) "2016 Feb-2017 Dec", "2016-2017", "Mo,Tu,Th,Fr 12:00-18:00;Sa 12:00-17:00; Th[3] off; Th[-1] off", - "Sep 15+Sa-Oct Su[1]; Oct 01-03" // Oktoberfest - }; + "Sep 15+Sa-Oct Su[1]; Oct 01-03", // Oktoberfest + "Aug 15-Jun 15: Mo-Fr 07:30-09:30,13:30-15:30", + "Mo-Fr 07:00-08:30,14:30-15:30; SH off", + "Jun 07: 08:30"}; for (auto &input : opening_hours) { @@ -78,7 +80,8 @@ BOOST_AUTO_TEST_CASE(check_opening_hours_grammar_incorrect_correct) "Fr-Sa 20:00-04:00", "Tu-Th 20:00-03:00 open \"Club and bar\"; Fr-Sa 20:00-04:00 open \"Club and bar\" || " "Su-Mo 18:00-02:00 open \"bar\" || Tu-Th 18:00-03:00 open \"bar\" || Fr-Sa 18:00-04:00 " - "open \"bar\""}}; + "open \"bar\""}, + {"Jun 07:08:30", "Jun 07:08"}}; for (auto &input : opening_hours) { @@ -290,4 +293,25 @@ BOOST_AUTO_TEST_CASE(check_opening_hours_extended_hours_nonoverlapping) BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Thu, 22 Dec 2016 20:00:00")), false); } +BOOST_AUTO_TEST_CASE(check_opening_hours_inverted_date_range) +{ + const auto &opening_hours = ParseOpeningHours("Aug 15-Jun 15: Mo-Fr 07:30-09:30,13:30-15:30"); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Tue, 03 Jul 2018 07:00:00")), false); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Tue, 03 Jul 2018 09:00:00")), false); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Tue, 03 Apr 2018 09:00:00")), true); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Mon, 03 Sep 2018 14:00:00")), true); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Fri, 13 Jun 2018 09:00:00")), true); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Mon, 16 Jun 2018 09:00:00")), false); +} + +BOOST_AUTO_TEST_CASE(check_opening_hours_school_hours) +{ + const auto &opening_hours = ParseOpeningHours("Mo-Fr 07:00-08:30,14:30-15:30; SH off"); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Tue, 03 Jul 2018 06:00:00")), false); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Tue, 03 Jul 2018 09:00:00")), false); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Tue, 03 Apr 2018 08:00:00")), true); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Mon, 03 Sep 2018 15:00:00")), true); + BOOST_CHECK_EQUAL(CheckOpeningHours(opening_hours, time("Sun, 02 Sep 2018 15:00:00")), false); +} + BOOST_AUTO_TEST_SUITE_END()