Rewrite osmoh::Time, osmoh::Timespan. Rewrite time_selector.

This commit is contained in:
Sergey Magidovich 2015-10-19 18:15:53 +03:00
parent b8970aa481
commit 2fd6a8cdf7
5 changed files with 1538 additions and 1160 deletions

View file

@ -1,45 +1,44 @@
#include "osm_time_range.hpp"
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/adapted/adt/adapt_adt.hpp>
BOOST_FUSION_ADAPT_STRUCT
BOOST_FUSION_ADAPT_ADT
(
osmoh::Time,
(uint8_t, hours)
(uint8_t, minutes)
(uint8_t, flags)
(osmoh::Time::THours, osmoh::Time::THours, obj.GetHours(), obj.SetHours(val))
(osmoh::Time::TMinutes, osmoh::Time::TMinutes, obj.GetMinutes(), obj.SetMinutes(val))
(osmoh::Time::EEvent, osmoh::Time::EEvent, obj.GetEvent(), obj.SetEvent(val))
)
BOOST_FUSION_ADAPT_STRUCT
BOOST_FUSION_ADAPT_ADT
(
osmoh::TimeSpan,
(osmoh::Time, from)
(osmoh::Time, to)
(uint8_t, flags)
(osmoh::Time, period)
osmoh::Timespan,
(osmoh::Time const &, osmoh::Time const &, obj.GetStart(), obj.SetStart(val))
(osmoh::Time const &, osmoh::Time const & , obj.GetEnd(), obj.SetEnd(val))
(osmoh::Time const &, osmoh::Time const &, obj.GetPeriod(), obj.SetPeriod(val))
(bool, bool, obj.HasPlus(), obj.SetPlus(val))
)
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::Weekday,
(uint8_t, weekdays)
(uint16_t, nth)
(int32_t, offset)
)
// BOOST_FUSION_ADAPT_STRUCT
// (
// osmoh::Weekday,
// (uint8_t, weekdays)
// (uint16_t, nth)
// (int32_t, offset)
// )
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::State,
(uint8_t, state)
(std::string, comment)
)
// BOOST_FUSION_ADAPT_STRUCT
// (
// osmoh::State,
// (uint8_t, state)
// (std::string, comment)
// )
BOOST_FUSION_ADAPT_STRUCT
(
osmoh::TimeRule,
(osmoh::TWeekdays, weekdays)
(osmoh::TTimeSpans, timespan)
(osmoh::State, state)
(uint8_t, int_flags)
)
// BOOST_FUSION_ADAPT_STRUCT
// (
// osmoh::TimeRule,
// (osmoh::TWeekdays, weekdays)
// (osmoh::TTimeSpans, timespan)
// (osmoh::State, state)
// (uint8_t, int_flags)
// )

View file

@ -21,6 +21,7 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <osm_time_range.hpp>
#include <osm_parsers.hpp>
@ -56,7 +57,7 @@ bool test(Char const * in, Parser const & p, bool full_match = true)
return boost::spirit::qi::parse(in, last, p) && (!full_match || (in == last));
}
template <template <typename> class Parser, typename Char>
template <template <typename> class Parser, typename ParseResult, typename Char>
std::basic_string<Char> ParseAndUnparse(Char const * input)
{
// we don't care about the result of the "what" function.
@ -65,30 +66,27 @@ std::basic_string<Char> ParseAndUnparse(Char const * input)
using boost::spirit::qi::phrase_parse;
using boost::spirit::standard_wide::space;
// TODO move to template
osmoh::TTimeRules timeRules;
ParseResult parseResult;
std::basic_string<Char> const str(input);
Parser<decltype(begin(str))> p;
boost::spirit::qi::what(p);
auto first = begin(str);
auto const last = end(str);
auto parsed = boost::spirit::qi::phrase_parse(
begin(str),
end(str),
first,
last,
p,
space,
timeRules);
parseResult);
if (!parsed)
if (!parsed || first != last)
return {};
std::basic_stringstream<Char> sstr;
for (auto it = begin(timeRules); it != end(timeRules); ++it)
{
sstr << (*it);
if (next(it) != end(timeRules))
sstr << ' ';
}
sstr << parseResult;
return sstr.str();
}
@ -121,429 +119,472 @@ BOOST_AUTO_TEST_CASE(OpeningHours_Locale)
std::locale::global(prev);
}
BOOST_AUTO_TEST_CASE(OpeningHours_TimeHit)
BOOST_AUTO_TEST_CASE(OpeningHours_ParseUnparse)
{
{
OSMTimeRange oh = OSMTimeRange::FromString("06:13-15:00; 16:30+");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("12-12-2013 7:00").IsOpen());
BOOST_CHECK(oh.UpdateState("12-12-2013 16:00").IsClosed());
BOOST_CHECK(oh.UpdateState("12-12-2013 20:00").IsOpen());
auto const rule = "06:00";
auto const parsedUnparsed = ParseAndUnparse<osmoh::parsing::time_selector,
osmoh::TTimespans>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
{
OSMTimeRange oh = OSMTimeRange::FromString("We-Sa; Mo[1,3] closed; Su[-1,-2] closed; Fr[2] open; Fr[-2], Fr open; Su[-2] -2 days");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("20-03-2015 18:00").IsOpen());
BOOST_CHECK(oh.UpdateState("17-03-2015 18:00").IsClosed());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("We-Fr; Mo[1,3] closed; Su[-1,-2] closed");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("20-03-2015 18:00").IsOpen());
BOOST_CHECK(oh.UpdateState("17-03-2015 18:00").IsClosed());
auto const rule = "06:00+";
auto const parsedUnparsed = ParseAndUnparse<osmoh::parsing::time_selector,
osmoh::TTimespans>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
{
OSMTimeRange oh = OSMTimeRange::FromString("We-Fr; Mo[1,3] +1 day closed; Su[-1,-2] -3 days closed");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("20-03-2015 18:00").IsOpen());
BOOST_CHECK(oh.UpdateState("17-03-2015 18:00").IsClosed());
auto const rule = "06:00-02:00";
auto const parsedUnparsed = ParseAndUnparse<osmoh::parsing::time_selector,
osmoh::TTimespans>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo-Su 14:30-17:00; Mo[1] closed; Su[-1] closed");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("09-03-2015 16:00").IsOpen());
BOOST_CHECK(oh.UpdateState("02-03-2015 16:00").IsClosed());
BOOST_CHECK(oh.UpdateState("22-03-2015 16:00").IsOpen());
BOOST_CHECK(oh.UpdateState("29-03-2015 16:00").IsClosed());
auto const rule = "06:00-02:00+";
auto const parsedUnparsed = ParseAndUnparse<osmoh::parsing::time_selector,
osmoh::TTimespans>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
{
OSMTimeRange oh = OSMTimeRange::FromString("PH,Tu-Su 10:00-18:00; Sa[1] 10:00-18:00 open \"Eintritt ins gesamte Haus frei\"; Jan 1,Dec 24,Dec 25,easter -2 days: closed");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("03-03-2015 16:00").IsOpen());
BOOST_CHECK(oh.Comment().empty());
BOOST_CHECK(oh.UpdateState("07-03-2015 16:00").IsOpen());
BOOST_CHECK(oh.Comment().empty() == false);
auto const rule = "06:00-02:00/03";
auto const parsedUnparsed = ParseAndUnparse<osmoh::parsing::time_selector,
osmoh::TTimespans>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo-Su 11:00+; Mo [1,3] off");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("04-03-2015 16:00").IsOpen());
BOOST_CHECK(oh.UpdateState("09-03-2015 16:00").IsOpen());
BOOST_CHECK(oh.UpdateState("02-03-2015 16:00").IsClosed());
BOOST_CHECK(oh.UpdateState("16-03-2015 16:00").IsClosed());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("08:00-16:00 open, 16:00-03:00 open \"public room\"");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("01-03-2015 20:00").IsOpen());
BOOST_CHECK(oh.UpdateState("01-03-2015 20:00").Comment() == "public room");
}
{
OSMTimeRange oh = OSMTimeRange::FromString("9:0002:00");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("01-01-2000 07:00").IsClosed());
BOOST_CHECK(oh.UpdateState("01-01-2000 09:00").IsOpen());
BOOST_CHECK(oh.UpdateState("01-01-2000 12:00").IsOpen());
BOOST_CHECK(oh.UpdateState("01-01-2000 20:00").IsOpen());
BOOST_CHECK(oh.UpdateState("01-01-2000 24:00").IsOpen());
BOOST_CHECK(oh.UpdateState("01-01-2000 00:00").IsOpen());
BOOST_CHECK(oh.UpdateState("01-01-2000 01:00").IsOpen());
BOOST_CHECK(oh.UpdateState("01-01-2000 01:59").IsOpen());
BOOST_CHECK(oh.UpdateState("01-01-2000 02:00").IsClosed());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00am-19:00pm"); // hours > 12, ignore pm
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("01-01-2000 20:00").IsClosed());
BOOST_CHECK(oh.UpdateState("01-01-2000 8:00").IsClosed());
BOOST_CHECK(oh.UpdateState("01-01-2000 14:00").IsOpen());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00h-7:00 pm"); // symbols case
BOOST_CHECK(oh.IsValid());
BOOST_CHECK(oh.UpdateState("01-01-2000 20:00").IsClosed());
BOOST_CHECK(oh.UpdateState("01-01-2000 8:00").IsClosed());
BOOST_CHECK(oh.UpdateState("01-01-2000 14:00").IsOpen());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo-Fr: 11-19 Uhr;Sa: 10-18 Uhr");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK_EQUAL(oh.UpdateState("08-03-2015 20:00").IsClosed(), true);
BOOST_CHECK_EQUAL(oh.UpdateState("18-03-2015 12:00").IsClosed(), false);
BOOST_CHECK_EQUAL(oh.UpdateState("16-03-2015 10:00").IsOpen(), false);
BOOST_CHECK(oh.UpdateState("14-03-2015 10:00").IsOpen());
BOOST_CHECK(oh.UpdateState("16-03-2015 11:00").IsOpen());
BOOST_CHECK(oh.UpdateState("01-01-2000 14:00").IsOpen());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Apr 9-19");
BOOST_CHECK(oh.IsValid());
BOOST_CHECK_EQUAL(oh.UpdateState("01-01-2000 20:00").IsClosed(), false);
BOOST_CHECK_EQUAL(oh.UpdateState("01-01-2000 8:00").IsClosed(), false);
BOOST_CHECK(oh.UpdateState("01-01-2000 14:00").IsOpen());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("9-19"); // it's no time, it's days of month
BOOST_CHECK(oh.IsValid());
BOOST_CHECK_EQUAL(oh.UpdateState("01-01-2000 20:00").IsClosed(), false);
BOOST_CHECK_EQUAL(oh.UpdateState("01-01-2000 8:00").IsClosed(), false);
BOOST_CHECK(oh.UpdateState("01-01-2000 14:00").IsOpen());
}
}
BOOST_AUTO_TEST_CASE(OpeningHours_StaticSet)
{
{
// TODO(mgsergio) move validation from parsing
// OSMTimeRange oh = OSMTimeRange::FromString("06:00-02:00/21:03");
// BOOST_CHECK(oh.IsValid());
auto const rule = "06:00-02:00/21:03";
BOOST_CHECK_EQUAL(ParseAndUnparse<osmoh::parsing::time_domain>(rule), rule);
auto const parsedUnparsed = ParseAndUnparse<osmoh::parsing::time_selector,
osmoh::TTimespans>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
{
// BOOST_CHECK(test_hard<osmoh::parsing::time_domain>("06:00-09:00/03"));
//BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("06:00-07:00/03");
BOOST_CHECK(oh.IsValid() == false);
}
{
OSMTimeRange oh = OSMTimeRange::FromString("sunrise-sunset");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Su-Th sunset-24:00, 04:00-sunrise; Fr-Sa sunset-sunrise");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep Su [1,3] 14:30-17:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("06:00+");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("06:00-07:00+");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("24/7");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("06:13-15:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo-Su 08:00-23:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("(sunrise+02:00)-(sunset-04:12)");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo-Sa; PH off");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Jan-Mar 07:00-19:00;Apr-Sep 07:00-22:00;Oct-Dec 07:00-19:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo closed");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("06:00-23:00 open \"Dining in\"");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("06:00-23:00 open \"Dining in\" || 00:00-24:00 open \"Drive-through\"");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("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\"");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00-21:00 \"call us\"");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("10:00-13:30,17:00-20:30");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep: Mo-Fr 09:00-13:00,14:00-18:00; Apr-Sep: Sa 10:00-13:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo,We,Th,Fr 12:00-18:00; Sa-Su 12:00-17:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Su-Th 11:00-03:00, Fr-Sa 11:00-05:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo-We 17:00-01:00, Th,Fr 15:00-01:00; PH off");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Tu-Su 10:00-18:00, Mo 12:00-17:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("sunset-sunrise");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("9:0022:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("jun 16-mar 14 sunrise-sunset");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Sa-Su; PH");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Su; PH");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo-Sa; PH off");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo-Sa; PH off");
BOOST_CHECK(oh.IsValid());
}
{
// TODO(mgsergio) Check if we need locale. // пн -> Пн
OSMTimeRange oh = OSMTimeRange::FromString("пн. — пт.: 09:00 — 21:00; сб.: 09:00 — 19:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("May 15-Sep 23 10:00-18:00; Sep 24 - May 14 \"by appointment\"");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("May-Aug: Mo-Sa 14:30-Sunset; Su 10:30-Sunset; Sep-Apr off");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("May-Oct; Nov-Apr off");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Fr-Sa");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Apr 01-Oct 03: Mo-Th 07:00-20:00; Apr 01-Oct 03: Fr-Su 07:00-21:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Apr 01-Oct 14 07:00-13:00, 15:00-22:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("06:00-08:30; 15:30-16:30");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep: sunrise-sunset; Dec 1-20: dusk-dawn off");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep: sunrise-sunset; Jan 1 off; Dec 25-26 off");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep: sunrise-sunset; Jan 1: off; Dec 25-26: off");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo-Fr: 09:00-18:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep sunrise-sunset; Dec 1-20 dusk-dawn off");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo off; Tu-Sa 09:30-19:00; Su 10:00-14:30; Jan 1 off; Dec 25-26 off");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo-Th 08:00-19:00, Fr 08:00-17:00, Su[-2] 08:00-15:00");
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Lu-Di 10:00-18:00"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("sunset-sunrise; Sa 09:00-18:00;TU,su,pH OFF"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00h-19:00 h"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00h to 19:00 h"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09h to 19:00"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("9h-19h"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("9am-9pm"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00H-19:00 h"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00am-19:00"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00-19:00;Sa 09:00-18:00;Tu,Su,PH OFF"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00-19:00;Sa 09:00-18:00;Tu,Su,ph Off"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("05:00 22:00"); // long dash instead minus
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("05:00 - 22:00"); // minus
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00-20:00 open \"Bei schönem Wetter. Falls unklar kann angerufen werden\""); // charset
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00-22:00; Tu off; dec 31 off; Jan 1 off"); // symbols case
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("9:00-22:00"); // leading zeros
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("09:00-9:30"); // leading zeros
BOOST_CHECK(oh.IsValid());
}
{
OSMTimeRange oh = OSMTimeRange::FromString("Mo 08:00-11:00,14:00-17:00; Tu 08:00-11:00, 14:00-17:00; We 08:00-11:00; Th 08:00-11:00, 14:00-16:00; Fr 08:00-11:00");
BOOST_CHECK(oh.IsValid());
}
}
BOOST_AUTO_TEST_CASE( OpeningHours_CountFailed )
{
std::ifstream datalist("opening-count.lst");
BOOST_REQUIRE_MESSAGE(datalist.is_open(), "Can't open ./opening-count.lst: " << std::strerror(errno));
// BOOST_AUTO_TEST_CASE(OpeningHours_TimeHit)
// {
// {
// OSMTimeRange oh = OSMTimeRange::FromString("06:13-15:00; 16:30+");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("12-12-2013 7:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("12-12-2013 16:00").IsClosed());
// BOOST_CHECK(oh.UpdateState("12-12-2013 20:00").IsOpen());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("We-Sa; Mo[1,3] closed; Su[-1,-2] closed; Fr[2] open; Fr[-2], Fr open; Su[-2] -2 days");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("20-03-2015 18:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("17-03-2015 18:00").IsClosed());
// }
std::string line;
size_t line_num = 0;
size_t num_failed = 0;
size_t num_total = 0;
std::map<size_t, size_t> desc;
// {
// OSMTimeRange oh = OSMTimeRange::FromString("We-Fr; Mo[1,3] closed; Su[-1,-2] closed");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("20-03-2015 18:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("17-03-2015 18:00").IsClosed());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("We-Fr; Mo[1,3] +1 day closed; Su[-1,-2] -3 days closed");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("20-03-2015 18:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("17-03-2015 18:00").IsClosed());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo-Su 14:30-17:00; Mo[1] closed; Su[-1] closed");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("09-03-2015 16:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("02-03-2015 16:00").IsClosed());
// BOOST_CHECK(oh.UpdateState("22-03-2015 16:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("29-03-2015 16:00").IsClosed());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("PH,Tu-Su 10:00-18:00; Sa[1] 10:00-18:00 open \"Eintritt ins gesamte Haus frei\"; Jan 1,Dec 24,Dec 25,easter -2 days: closed");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("03-03-2015 16:00").IsOpen());
// BOOST_CHECK(oh.Comment().empty());
// BOOST_CHECK(oh.UpdateState("07-03-2015 16:00").IsOpen());
// BOOST_CHECK(oh.Comment().empty() == false);
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo-Su 11:00+; Mo [1,3] off");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("04-03-2015 16:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("09-03-2015 16:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("02-03-2015 16:00").IsClosed());
// BOOST_CHECK(oh.UpdateState("16-03-2015 16:00").IsClosed());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("08:00-16:00 open, 16:00-03:00 open \"public room\"");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("01-03-2015 20:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("01-03-2015 20:00").Comment() == "public room");
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("9:0002:00");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("01-01-2000 07:00").IsClosed());
// BOOST_CHECK(oh.UpdateState("01-01-2000 09:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("01-01-2000 12:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("01-01-2000 20:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("01-01-2000 24:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("01-01-2000 00:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("01-01-2000 01:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("01-01-2000 01:59").IsOpen());
// BOOST_CHECK(oh.UpdateState("01-01-2000 02:00").IsClosed());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00am-19:00pm"); // hours > 12, ignore pm
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("01-01-2000 20:00").IsClosed());
// BOOST_CHECK(oh.UpdateState("01-01-2000 8:00").IsClosed());
// BOOST_CHECK(oh.UpdateState("01-01-2000 14:00").IsOpen());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00h-7:00 pm"); // symbols case
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK(oh.UpdateState("01-01-2000 20:00").IsClosed());
// BOOST_CHECK(oh.UpdateState("01-01-2000 8:00").IsClosed());
// BOOST_CHECK(oh.UpdateState("01-01-2000 14:00").IsOpen());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo-Fr: 11-19 Uhr;Sa: 10-18 Uhr");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK_EQUAL(oh.UpdateState("08-03-2015 20:00").IsClosed(), true);
// BOOST_CHECK_EQUAL(oh.UpdateState("18-03-2015 12:00").IsClosed(), false);
// BOOST_CHECK_EQUAL(oh.UpdateState("16-03-2015 10:00").IsOpen(), false);
// BOOST_CHECK(oh.UpdateState("14-03-2015 10:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("16-03-2015 11:00").IsOpen());
// BOOST_CHECK(oh.UpdateState("01-01-2000 14:00").IsOpen());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Apr 9-19");
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK_EQUAL(oh.UpdateState("01-01-2000 20:00").IsClosed(), false);
// BOOST_CHECK_EQUAL(oh.UpdateState("01-01-2000 8:00").IsClosed(), false);
// BOOST_CHECK(oh.UpdateState("01-01-2000 14:00").IsOpen());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("9-19"); // it's no time, it's days of month
// BOOST_CHECK(oh.IsValid());
// BOOST_CHECK_EQUAL(oh.UpdateState("01-01-2000 20:00").IsClosed(), false);
// BOOST_CHECK_EQUAL(oh.UpdateState("01-01-2000 8:00").IsClosed(), false);
// BOOST_CHECK(oh.UpdateState("01-01-2000 14:00").IsOpen());
// }
// }
while (std::getline(datalist, line))
{
size_t count = 1;
std::string datastr;
// BOOST_AUTO_TEST_CASE(OpeningHours_StaticSet)
// {
// {
// // TODO(mgsergio) move validation from parsing
// // OSMTimeRange oh = OSMTimeRange::FromString("06:00-02:00/21:03");
// // BOOST_CHECK(oh.IsValid());
// auto const rule = "06:00-02:00/21:03";
// BOOST_CHECK_EQUAL(ParseAndUnparse<osmoh::parsing::time_domain>(rule), rule);
// }
auto d = line.find('|');
if (d == std::string::npos)
{
BOOST_WARN_MESSAGE((d != std::string::npos), "Incorrect line " << line_num << " format: " << line);
datastr = line;
}
else
{
count = std::stol(line.substr(0,d));
datastr = line.substr(d+1);
}
// {
// // BOOST_CHECK(test_hard<osmoh::parsing::time_domain>("06:00-09:00/03"));
// //BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("06:00-07:00/03");
// BOOST_CHECK(oh.IsValid() == false);
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("sunrise-sunset");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Su-Th sunset-24:00, 04:00-sunrise; Fr-Sa sunset-sunrise");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep Su [1,3] 14:30-17:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("06:00+");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("06:00-07:00+");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("24/7");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("06:13-15:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo-Su 08:00-23:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("(sunrise+02:00)-(sunset-04:12)");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo-Sa; PH off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Jan-Mar 07:00-19:00;Apr-Sep 07:00-22:00;Oct-Dec 07:00-19:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo closed");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("06:00-23:00 open \"Dining in\"");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("06:00-23:00 open \"Dining in\" || 00:00-24:00 open \"Drive-through\"");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("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\"");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00-21:00 \"call us\"");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("10:00-13:30,17:00-20:30");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep: Mo-Fr 09:00-13:00,14:00-18:00; Apr-Sep: Sa 10:00-13:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo,We,Th,Fr 12:00-18:00; Sa-Su 12:00-17:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Su-Th 11:00-03:00, Fr-Sa 11:00-05:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo-We 17:00-01:00, Th,Fr 15:00-01:00; PH off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Tu-Su 10:00-18:00, Mo 12:00-17:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("sunset-sunrise");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("9:0022:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("jun 16-mar 14 sunrise-sunset");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Sa-Su; PH");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Su; PH");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo-Sa; PH off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo-Sa; PH off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// // TODO(mgsergio) Check if we need locale. // пн -> Пн
// OSMTimeRange oh = OSMTimeRange::FromString("пн. — пт.: 09:00 — 21:00; сб.: 09:00 — 19:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("May 15-Sep 23 10:00-18:00; Sep 24 - May 14 \"by appointment\"");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("May-Aug: Mo-Sa 14:30-Sunset; Su 10:30-Sunset; Sep-Apr off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("May-Oct; Nov-Apr off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Fr-Sa");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Apr 01-Oct 03: Mo-Th 07:00-20:00; Apr 01-Oct 03: Fr-Su 07:00-21:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Apr 01-Oct 14 07:00-13:00, 15:00-22:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("06:00-08:30; 15:30-16:30");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep: sunrise-sunset; Dec 1-20: dusk-dawn off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep: sunrise-sunset; Jan 1 off; Dec 25-26 off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep: sunrise-sunset; Jan 1: off; Dec 25-26: off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo-Fr: 09:00-18:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Apr-Sep sunrise-sunset; Dec 1-20 dusk-dawn off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo off; Tu-Sa 09:30-19:00; Su 10:00-14:30; Jan 1 off; Dec 25-26 off");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo-Th 08:00-19:00, Fr 08:00-17:00, Su[-2] 08:00-15:00");
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Lu-Di 10:00-18:00"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("sunset-sunrise; Sa 09:00-18:00;TU,su,pH OFF"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00h-19:00 h"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00h to 19:00 h"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09h to 19:00"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("9h-19h"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("9am-9pm"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00H-19:00 h"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00am-19:00"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00-19:00;Sa 09:00-18:00;Tu,Su,PH OFF"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00-19:00;Sa 09:00-18:00;Tu,Su,ph Off"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("05:00 22:00"); // long dash instead minus
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("05:00 - 22:00"); // minus
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00-20:00 open \"Bei schönem Wetter. Falls unklar kann angerufen werden\""); // charset
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00-22:00; Tu off; dec 31 off; Jan 1 off"); // symbols case
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("9:00-22:00"); // leading zeros
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("09:00-9:30"); // leading zeros
// BOOST_CHECK(oh.IsValid());
// }
// {
// OSMTimeRange oh = OSMTimeRange::FromString("Mo 08:00-11:00,14:00-17:00; Tu 08:00-11:00, 14:00-17:00; We 08:00-11:00; Th 08:00-11:00, 14:00-16:00; Fr 08:00-11:00");
// BOOST_CHECK(oh.IsValid());
// }
// }
line_num++;
OSMTimeRange oh = OSMTimeRange::FromString(datastr);
if (!oh.IsValid()) {
num_failed += count;
desc[count]++;
BOOST_TEST_MESSAGE("-- " << count << " :[" << datastr << "]");
}
num_total += count;
}
BOOST_CHECK_MESSAGE((num_failed == 0), "Failed " << num_failed << " of " << num_total << " (" << double(num_failed)/(double(num_total)/100) << "%)");
std::stringstream desc_message;
for (auto const & e : desc) {
desc_message << "Weight: " << e.first << " Count: " << e.second << std::endl;
}
BOOST_TEST_MESSAGE(desc_message.str());
}
// BOOST_AUTO_TEST_CASE( OpeningHours_CountFailed )
// {
// std::ifstream datalist("opening-count.lst");
// BOOST_REQUIRE_MESSAGE(datalist.is_open(), "Can't open ./opening-count.lst: " << std::strerror(errno));
// std::string line;
// size_t line_num = 0;
// size_t num_failed = 0;
// size_t num_total = 0;
// std::map<size_t, size_t> desc;
// while (std::getline(datalist, line))
// {
// size_t count = 1;
// std::string datastr;
// auto d = line.find('|');
// if (d == std::string::npos)
// {
// BOOST_WARN_MESSAGE((d != std::string::npos), "Incorrect line " << line_num << " format: " << line);
// datastr = line;
// }
// else
// {
// count = std::stol(line.substr(0,d));
// datastr = line.substr(d+1);
// }
// line_num++;
// OSMTimeRange oh = OSMTimeRange::FromString(datastr);
// if (!oh.IsValid()) {
// num_failed += count;
// desc[count]++;
// BOOST_TEST_MESSAGE("-- " << count << " :[" << datastr << "]");
// }
// num_total += count;
// }
// BOOST_CHECK_MESSAGE((num_failed == 0), "Failed " << num_failed << " of " << num_total << " (" << double(num_failed)/(double(num_total)/100) << "%)");
// std::stringstream desc_message;
// for (auto const & e : desc) {
// desc_message << "Weight: " << e.first << " Count: " << e.second << std::endl;
// }
// BOOST_TEST_MESSAGE(desc_message.str());
// }

View file

@ -11,6 +11,8 @@
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#if defined(__clang__)
#pragma clang diagnostic push
@ -41,42 +43,42 @@ class test_impl
};
phx::function<test_impl> const test = test_impl();
inline boost::posix_time::time_period make_time_period(boost::gregorian::date const & d,
osmoh::TimeSpan const & ts)
{
using boost::posix_time::ptime;
using boost::posix_time::hours;
using boost::posix_time::minutes;
using boost::posix_time::time_period;
// inline boost::posix_time::time_period make_time_period(boost::gregorian::date const & d,
// osmoh::TimeSpan const & ts)
// {
// using boost::posix_time::ptime;
// using boost::posix_time::hours;
// using boost::posix_time::minutes;
// using boost::posix_time::time_period;
/// TODO(yershov@): Need create code for calculate real values
ptime sunrise(d, hours(6));
ptime sunset(d, hours(19));
// /// TODO(yershov@): Need create code for calculate real values
// ptime sunrise(d, hours(6));
// ptime sunset(d, hours(19));
ptime t1, t2;
// ptime t1, t2;
if (ts.from.flags & osmoh::Time::eSunrise)
t1 = sunrise;
else if (ts.from.flags & osmoh::Time::eSunset)
t1 = sunset;
else
t1 = ptime(d, hours((ts.from.flags & osmoh::Time::eHours) ? ts.from.hours : 0) + minutes((ts.from.flags & osmoh::Time::eMinutes) ? ts.from.minutes : 0));
// if (ts.from.flags & osmoh::Time::eSunrise)
// t1 = sunrise;
// else if (ts.from.flags & osmoh::Time::eSunset)
// t1 = sunset;
// else
// t1 = ptime(d, hours((ts.from.flags & osmoh::Time::eHours) ? ts.from.hours : 0) + minutes((ts.from.flags & osmoh::Time::eMinutes) ? ts.from.minutes : 0));
t2 = t1;
// t2 = t1;
if (ts.to.flags & osmoh::Time::eSunrise)
t2 = sunrise;
else if (ts.to.flags & osmoh::Time::eSunset)
t2 = sunset;
else
{
t2 = ptime(d, hours((ts.to.flags & osmoh::Time::eHours) ? ts.to.hours : 24) + minutes((ts.to.flags & osmoh::Time::eMinutes) ? ts.to.minutes : 0));
if (t2 < t1)
t2 += hours(24);
}
// if (ts.to.flags & osmoh::Time::eSunrise)
// t2 = sunrise;
// else if (ts.to.flags & osmoh::Time::eSunset)
// t2 = sunset;
// else
// {
// t2 = ptime(d, hours((ts.to.flags & osmoh::Time::eHours) ? ts.to.hours : 24) + minutes((ts.to.flags & osmoh::Time::eMinutes) ? ts.to.minutes : 0));
// if (t2 < t1)
// t2 += hours(24);
// }
return time_period(t1, t2);
}
// return time_period(t1, t2);
// }
namespace parsing
{
@ -94,18 +96,21 @@ class dash_ : public qi::symbols<wchar_t>
add
(L"-")
/* not standard */
(L"")(L"")(L"")(L"~")(L"")(L"")(L"to")(L"às")(L"ás")(L"as")(L"a")(L"ate")(L"bis")
// (L"")(L"—")(L"")(L"~")(L"")(L"〜")(L"to")(L"às")(L"ás")(L"as")(L"a")(L"ate")(L"bis")
;
}
} dash;
class event_ : public qi::symbols<wchar_t, uint8_t>
class event_ : public qi::symbols<char, osmoh::Time::EEvent>
{
public:
event_()
{
add
(L"dawn", osmoh::Time::eSunrise)(L"sunrise", osmoh::Time::eSunrise)(L"sunset", osmoh::Time::eSunset)(L"dusk", osmoh::Time::eSunset)
("dawn", osmoh::Time::EEvent::eSunrise)
("sunrise", osmoh::Time::EEvent::eSunrise)
("sunset", osmoh::Time::EEvent::eSunset)
("dusk", osmoh::Time::EEvent::eSunset)
;
}
} event;
@ -116,16 +121,16 @@ struct wdays_ : qi::symbols<wchar_t, unsigned>
{
add
(L"mo", 0)(L"tu", 1)(L"we", 2)(L"th", 3)(L"fr", 4)(L"sa", 5)(L"su", 6) // en
(L"mon", 0)(L"tue", 1)(L"wed", 2)(L"thu", 3)(L"fri", 4)(L"sat", 5)(L"sun", 6) // en
(L"пн", 0)(L"вт", 1)(L"ср", 2)(L"чт", 3)(L"пт", 4)(L"сб", 5)(L"вс", 6) // ru
(L"пн.", 0)(L"вт.", 1)(L"ср.", 2)(L"чт.", 3)(L"пт.", 4)(L"сб.", 5)(L"вс.", 6) // ru
(L"lu", 0)(L"ma", 1)(L"me", 2)(L"je", 3)(L"ve", 4)(L"sa", 5)(L"di", 6) // fr
(L"lu", 0)(L"ma", 1)(L"me", 2)(L"gi", 3)(L"ve", 4)(L"sa", 5)(L"do", 6) // it
(L"lu", 0)(L"ma", 1)(L"mi", 2)(L"ju", 3)(L"vie", 4)(L"", 5)(L"do", 6) // sp
(L"週一", 0)(L"週二", 1)(L"週三", 2)(L"週四", 3)(L"週五", 4)(L"週六", 5)(L"週日", 6) // ch traditional
(L"senin", 0)(L"selasa", 1)(L"rabu", 2)(L"kamis", 3)(L"jum'at", 4)(L"sabtu", 5)(L"minggu", 6) // indonesian
// (L"mon", 0)(L"tue", 1)(L"wed", 2)(L"thu", 3)(L"fri", 4)(L"sat", 5)(L"sun", 6) // en
// (L"пн", 0)(L"вт", 1)(L"ср", 2)(L"чт", 3)(L"пт", 4)(L"сб", 5)(L"вс", 6) // ru
// (L"пн.", 0)(L"вт.", 1)(L"ср.", 2)(L"чт.", 3)(L"пт.", 4)(L"сб.", 5)(L"вс.", 6) // ru
// (L"lu", 0)(L"ma", 1)(L"me", 2)(L"je", 3)(L"ve", 4)(L"sa", 5)(L"di", 6) // fr
// (L"lu", 0)(L"ma", 1)(L"me", 2)(L"gi", 3)(L"ve", 4)(L"sa", 5)(L"do", 6) // it
// (L"lu", 0)(L"ma", 1)(L"mi", 2)(L"ju", 3)(L"vie", 4)(L"sá", 5)(L"do", 6) // sp
// (L"週一", 0)(L"週二", 1)(L"週三", 2)(L"週四", 3)(L"週五", 4)(L"週六", 5)(L"週日", 6) // ch traditional
// (L"senin", 0)(L"selasa", 1)(L"rabu", 2)(L"kamis", 3)(L"jum'at", 4)(L"sabtu", 5)(L"minggu", 6) // indonesian
(L"wd", 2)
// (L"wd", 2)
;
}
@ -142,46 +147,46 @@ struct month_ : qi::symbols<wchar_t, unsigned>
}
} month;
struct hours_ : qi::symbols<char, uint8_t>
struct hours_ : qi::symbols<char, osmoh::Time::THours>
{
hours_()
{
add
( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0)("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)
// ( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0_h)("01", 1_h)("02", 2_h)("03", 3_h)("04", 4_h)("05", 5_h)("06", 6_h)("07", 7_h)("08", 8_h)("09", 9_h)
("10", 10_h)("11", 11_h)("12", 12_h)("13", 13_h)("14", 14_h)("15", 15_h)("16", 16_h)("17", 17_h)("18", 18_h)("19", 19_h)
("20", 20_h)("21", 21_h)("22", 22_h)("23", 23_h)("24", 24_h)
;
}
} hours;
struct exthours_ : qi::symbols<char, uint8_t>
struct exthours_ : qi::symbols<char, osmoh::Time::THours>
{
exthours_()
{
add
( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0)("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
("30", 30)("31", 31)("32", 32)("33", 33)("34", 34)("35", 35)("36", 36)("37", 37)("38", 38)("39", 39)
("40", 40)("41", 41)("42", 42)("43", 43)("44", 44)("45", 45)("46", 46)("47", 47)("48", 48)
// ( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0_h)("01", 1_h)("02", 2_h)("03", 3_h)("04", 4_h)("05", 5_h)("06", 6_h)("07", 7_h)("08", 8_h)("09", 9_h)
("10", 10_h)("11", 11_h)("12", 12_h)("13", 13_h)("14", 14_h)("15", 15_h)("16", 16_h)("17", 17_h)("18", 18_h)("19", 19_h)
("20", 20_h)("21", 21_h)("22", 22_h)("23", 23_h)("24", 24_h)("25", 25_h)("26", 26_h)("27", 27_h)("28", 28_h)("29", 29_h)
("30", 30_h)("31", 31_h)("32", 32_h)("33", 33_h)("34", 34_h)("35", 35_h)("36", 36_h)("37", 37_h)("38", 38_h)("39", 39_h)
("40", 40_h)("41", 41_h)("42", 42_h)("43", 43_h)("44", 44_h)("45", 45_h)("46", 46_h)("47", 47_h)("48", 48_h)
;
}
} exthours;
struct minutes_ : qi::symbols<char, uint8_t>
struct minutes_ : qi::symbols<char, osmoh::Time::TMinutes>
{
minutes_()
{
add
( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0)("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
("30", 30)("31", 31)("32", 32)("33", 33)("34", 34)("35", 35)("36", 36)("37", 37)("38", 38)("39", 39)
("40", 40)("41", 41)("42", 42)("43", 43)("44", 44)("45", 45)("46", 46)("47", 47)("48", 48)("49", 49)
("50", 50)("51", 51)("52", 52)("53", 53)("54", 54)("55", 55)("56", 56)("57", 57)("58", 58)("59", 59)
// ( "0", 0)( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9) /* not standard */
("00", 0_min)("01", 1_min)("02", 2_min)("03", 3_min)("04", 4_min)("05", 5_min)("06", 6_min)("07", 7_min)("08", 8_min)("09", 9_min)
("10", 10_min)("11", 11_min)("12", 12_min)("13", 13_min)("14", 14_min)("15", 15_min)("16", 16_min)("17", 17_min)("18", 18_min)("19", 19_min)
("20", 20_min)("21", 21_min)("22", 22_min)("23", 23_min)("24", 24_min)("25", 25_min)("26", 26_min)("27", 27_min)("28", 28_min)("29", 29_min)
("30", 30_min)("31", 31_min)("32", 32_min)("33", 33_min)("34", 34_min)("35", 35_min)("36", 36_min)("37", 37_min)("38", 38_min)("39", 39_min)
("40", 40_min)("41", 41_min)("42", 42_min)("43", 43_min)("44", 44_min)("45", 45_min)("46", 46_min)("47", 47_min)("48", 48_min)("49", 49_min)
("50", 50_min)("51", 51_min)("52", 52_min)("53", 53_min)("54", 54_min)("55", 55_min)("56", 56_min)("57", 57_min)("58", 58_min)("59", 59_min)
;
}
} minutes;
@ -191,7 +196,7 @@ struct weeknum_ : qi::symbols<char, unsigned>
weeknum_()
{
add
( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9)
// ( "1", 1)( "2", 2)( "3", 3)( "4", 4)( "5", 5)( "6", 6)( "7", 7)( "8", 8)( "9", 9)
("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
@ -207,7 +212,7 @@ struct daynum_ : qi::symbols<char, unsigned>
daynum_()
{
add
("1", 1)("2", 2)("3", 3)("4", 4)("5", 5)("6", 6)("7", 7)("8", 8)("9", 9)
// ("1", 1)("2", 2)("3", 3)("4", 4)("5", 5)("6", 6)("7", 7)("8", 8)("9", 9)
("01", 1)("02", 2)("03", 3)("04", 4)("05", 5)("06", 6)("07", 7)("08", 8)("09", 9)
("10", 10)("11", 11)("12", 12)("13", 13)("14", 14)("15", 15)("16", 16)("17", 17)("18", 18)("19", 19)
("20", 20)("21", 21)("22", 22)("23", 23)("24", 24)("25", 25)("26", 26)("27", 27)("28", 28)("29", 29)
@ -216,202 +221,202 @@ struct daynum_ : qi::symbols<char, unsigned>
}
} daynum;
template <class Iterator>
class year_selector : public qi::grammar<Iterator, space_type>
{
protected:
qi::rule<Iterator, space_type> year;
qi::rule<Iterator, space_type> year_range;
qi::rule<Iterator, space_type> main;
public:
year_selector() : year_selector::base_type(main)
{
using qi::uint_;
using qi::lit;
using charset::char_;
// template <class Iterator>
// class year_selector : public qi::grammar<Iterator, space_type>
// {
// protected:
// qi::rule<Iterator, space_type> year;
// qi::rule<Iterator, space_type> year_range;
// qi::rule<Iterator, space_type> main;
// public:
// year_selector() : year_selector::base_type(main)
// {
// using qi::uint_;
// using qi::lit;
// using charset::char_;
static const qi::int_parser<unsigned, 10, 4, 4> _4digit = {};
// static const qi::int_parser<unsigned, 10, 4, 4> _4digit = {};
year %= _4digit;
year_range %= (year >> dash >> year >> '/' >> uint_)
| (year >> dash >> year)
| year >> char_('+')
| year
;
main %= year_range % ',';
}
};
// year %= _4digit;
// year_range %= (year >> dash >> year >> '/' >> uint_)
// | (year >> dash >> year)
// | year >> char_('+')
// | year
// ;
// main %= year_range % ',';
// }
// };
// template <typename Iterator>
// class week_selector : public qi::grammar<Iterator, space_type>
// {
// protected:
// qi::rule<Iterator, space_type> week;
// qi::rule<Iterator, space_type> year_range;
// qi::rule<Iterator, space_type> main;
// public:
// week_selector() : week_selector::base_type(main)
// {
// using qi::uint_;
// using qi::lit;
// using charset::char_;
// week %= (weeknum >> dash >> weeknum >> '/' >> uint_)
// | (weeknum >> dash >> weeknum)
// | weeknum
// ;
// main %= charset::no_case[lit("week")] >> week % ',';
// }
// };
// template <typename Iterator>
// class month_selector : public qi::grammar<Iterator, space_type>
// {
// protected:
// qi::rule<Iterator, space_type> date;
// qi::rule<Iterator, space_type> day_offset;
// qi::rule<Iterator, space_type> date_with_offsets;
// qi::rule<Iterator, space_type> monthday_range;
// qi::rule<Iterator, space_type> month_range;
// qi::rule<Iterator, space_type> main;
// public:
// month_selector() : month_selector::base_type(main)
// {
// using qi::int_;
// using qi::lit;
// using qi::double_;
// using qi::lexeme;
// using charset::char_;
// static const qi::int_parser<unsigned, 10, 4, 4> year = {};
// day_offset %= (char_('+') | char_('-')) >> int_ >> charset::no_case[(lit("days") | lit("day"))];
// date %= charset::no_case[(-year >> month >> daynum)]
// | (-year >> charset::no_case[lit("easter")])
// | daynum >> !(lit(':') >> qi::digit)
// ;
// date_with_offsets %= date >> -((char_('+') | char_('-')) >> charset::no_case[wdays] >> qi::no_skip[qi::space]) >> -day_offset;
// monthday_range %= (date_with_offsets >> dash >> date_with_offsets)
// | (date_with_offsets >> '+')
// | date_with_offsets
// | charset::no_case[(-year >> month >> dash >> month >> '/' >> int_)]
// | charset::no_case[(-year >> month >> dash >> month)]
// | charset::no_case[(-year >> month)]
// ;
// month_range %= charset::no_case[(month >> dash >> month)]
// | charset::no_case[month]
// ;
// main %= (monthday_range % ',') | (month_range % ',');
// BOOST_SPIRIT_DEBUG_NODE(main);
// BOOST_SPIRIT_DEBUG_NODE(month_range);
// BOOST_SPIRIT_DEBUG_NODE(monthday_range);
// BOOST_SPIRIT_DEBUG_NODE(date_with_offsets);
// BOOST_SPIRIT_DEBUG_NODE(date);
// BOOST_SPIRIT_DEBUG_NODE(day_offset);
// }
// };
// template <typename Iterator>
// class weekday_selector : public qi::grammar<Iterator, osmoh::TWeekdays(), space_type>
// {
// protected:
// qi::rule<Iterator, uint8_t(), space_type> nth;
// qi::rule<Iterator, uint16_t(), space_type> nth_entry;
// qi::rule<Iterator, int32_t(), space_type, qi::locals<int8_t>> day_offset;
// qi::rule<Iterator, space_type> holyday;
// qi::rule<Iterator, space_type> holiday_sequence;
// qi::rule<Iterator, osmoh::Weekday(), space_type> weekday_range;
// qi::rule<Iterator, osmoh::TWeekdays(), space_type> weekday_sequence;
// qi::rule<Iterator, osmoh::TWeekdays(), space_type> main;
// public:
// weekday_selector() : weekday_selector::base_type(main)
// {
// using qi::_a;
// using qi::_1;
// using qi::_2;
// using qi::_val;
// using qi::lit;
// using qi::ushort_;
// using boost::phoenix::at_c;
// nth %= ushort_(1) | ushort_(2) | ushort_(3) | ushort_(4) | ushort_(5);
// nth_entry = (nth >> dash >> nth) [_val |= ((2 << ((_2-1)-(_1-1))) - 1) << (_1-1)]
// | (lit('-') >> nth) [_val |= (0x0100 << (_1 - 1))]
// | nth [_val |= (1 << (_1 - 1))]
// ;
// day_offset = (lit('+')[_a = 1] | lit('-') [_a = -1]) >> ushort_[_val = _1*_a] >> charset::no_case[(lit(L"days") | lit(L"day"))];
// holyday %= (charset::no_case[lit(L"SH")] >> -day_offset) | charset::no_case[lit(L"PH")];
// holiday_sequence %= holyday % ',';
// weekday_range = (charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)]
// >> L'[' >> nth_entry[at_c<1>(_val) |= _1] % L','
// >> L']' >> day_offset[at_c<2>(_val) = _1])
// | (charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)] >> L'[' >> nth_entry[at_c<1>(_val) |= _1] % L',' >> L']')
// | charset::no_case[(wdays >> dash >> wdays)] [at_c<0>(_val) |= ((2 << ((_2)-(_1))) - 1) << (_1)]
// | charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)]
// ;
// weekday_sequence %= (weekday_range % L',') >> !qi::no_skip[charset::alpha] >> -lit(L':');
// main = (holiday_sequence >> -lit(L',') >> weekday_sequence[_val = _1])
// | weekday_sequence[_val = _1] >> -(-lit(L',') >> holiday_sequence)
// | holiday_sequence
// ;
// BOOST_SPIRIT_DEBUG_NODE(main);
// BOOST_SPIRIT_DEBUG_NODE(weekday_sequence);
// BOOST_SPIRIT_DEBUG_NODE(weekday_range);
// BOOST_SPIRIT_DEBUG_NODE(holiday_sequence);
// }
// };
template <typename Iterator>
class week_selector : public qi::grammar<Iterator, space_type>
class time_selector : public qi::grammar<Iterator, osmoh::TTimespans(), space_type>
{
protected:
qi::rule<Iterator, space_type> week;
qi::rule<Iterator, space_type> year_range;
qi::rule<Iterator, space_type> main;
public:
week_selector() : week_selector::base_type(main)
{
using qi::uint_;
using qi::lit;
using charset::char_;
week %= (weeknum >> dash >> weeknum >> '/' >> uint_)
| (weeknum >> dash >> weeknum)
| weeknum
;
main %= charset::no_case[lit("week")] >> week % ',';
}
};
template <typename Iterator>
class month_selector : public qi::grammar<Iterator, space_type>
{
protected:
qi::rule<Iterator, space_type> date;
qi::rule<Iterator, space_type> day_offset;
qi::rule<Iterator, space_type> date_with_offsets;
qi::rule<Iterator, space_type> monthday_range;
qi::rule<Iterator, space_type> month_range;
qi::rule<Iterator, space_type> main;
public:
month_selector() : month_selector::base_type(main)
{
using qi::int_;
using qi::lit;
using qi::double_;
using qi::lexeme;
using charset::char_;
static const qi::int_parser<unsigned, 10, 4, 4> year = {};
day_offset %= (char_('+') | char_('-')) >> int_ >> charset::no_case[(lit("days") | lit("day"))];
date %= charset::no_case[(-year >> month >> daynum)]
| (-year >> charset::no_case[lit("easter")])
| daynum >> !(lit(':') >> qi::digit)
;
date_with_offsets %= date >> -((char_('+') | char_('-')) >> charset::no_case[wdays] >> qi::no_skip[qi::space]) >> -day_offset;
monthday_range %= (date_with_offsets >> dash >> date_with_offsets)
| (date_with_offsets >> '+')
| date_with_offsets
| charset::no_case[(-year >> month >> dash >> month >> '/' >> int_)]
| charset::no_case[(-year >> month >> dash >> month)]
| charset::no_case[(-year >> month)]
;
month_range %= charset::no_case[(month >> dash >> month)]
| charset::no_case[month]
;
main %= (monthday_range % ',') | (month_range % ',');
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(month_range);
BOOST_SPIRIT_DEBUG_NODE(monthday_range);
BOOST_SPIRIT_DEBUG_NODE(date_with_offsets);
BOOST_SPIRIT_DEBUG_NODE(date);
BOOST_SPIRIT_DEBUG_NODE(day_offset);
}
};
template <typename Iterator>
class weekday_selector : public qi::grammar<Iterator, osmoh::TWeekdays(), space_type>
{
protected:
qi::rule<Iterator, uint8_t(), space_type> nth;
qi::rule<Iterator, uint16_t(), space_type> nth_entry;
qi::rule<Iterator, int32_t(), space_type, qi::locals<int8_t>> day_offset;
qi::rule<Iterator, space_type> holyday;
qi::rule<Iterator, space_type> holiday_sequence;
qi::rule<Iterator, osmoh::Weekday(), space_type> weekday_range;
qi::rule<Iterator, osmoh::TWeekdays(), space_type> weekday_sequence;
qi::rule<Iterator, osmoh::TWeekdays(), space_type> main;
public:
weekday_selector() : weekday_selector::base_type(main)
{
using qi::_a;
using qi::_1;
using qi::_2;
using qi::_val;
using qi::lit;
using qi::ushort_;
using boost::phoenix::at_c;
nth %= ushort_(1) | ushort_(2) | ushort_(3) | ushort_(4) | ushort_(5);
nth_entry = (nth >> dash >> nth) [_val |= ((2 << ((_2-1)-(_1-1))) - 1) << (_1-1)]
| (lit('-') >> nth) [_val |= (0x0100 << (_1 - 1))]
| nth [_val |= (1 << (_1 - 1))]
;
day_offset = (lit('+')[_a = 1] | lit('-') [_a = -1]) >> ushort_[_val = _1*_a] >> charset::no_case[(lit(L"days") | lit(L"day"))];
holyday %= (charset::no_case[lit(L"SH")] >> -day_offset) | charset::no_case[lit(L"PH")];
holiday_sequence %= holyday % ',';
weekday_range = (charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)]
>> L'[' >> nth_entry[at_c<1>(_val) |= _1] % L','
>> L']' >> day_offset[at_c<2>(_val) = _1])
| (charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)] >> L'[' >> nth_entry[at_c<1>(_val) |= _1] % L',' >> L']')
| charset::no_case[(wdays >> dash >> wdays)] [at_c<0>(_val) |= ((2 << ((_2)-(_1))) - 1) << (_1)]
| charset::no_case[wdays][at_c<0>(_val) |= (1<<_1)]
;
weekday_sequence %= (weekday_range % L',') >> !qi::no_skip[charset::alpha] >> -lit(L':');
main = (holiday_sequence >> -lit(L',') >> weekday_sequence[_val = _1])
| weekday_sequence[_val = _1] >> -(-lit(L',') >> holiday_sequence)
| holiday_sequence
;
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(weekday_sequence);
BOOST_SPIRIT_DEBUG_NODE(weekday_range);
BOOST_SPIRIT_DEBUG_NODE(holiday_sequence);
}
};
template <typename Iterator>
class time_selector : public qi::grammar<Iterator, osmoh::TTimeSpans(), space_type>
{
protected:
qi::rule<Iterator, osmoh::Time(), space_type, qi::locals<uint8_t>> hour_minutes;
qi::rule<Iterator, osmoh::Time(), space_type, qi::locals<uint8_t>> extended_hour_minutes;
qi::rule<Iterator, osmoh::Time(), space_type> hour_minutes;
qi::rule<Iterator, osmoh::Time(), space_type> extended_hour_minutes;
qi::rule<Iterator, osmoh::Time(), space_type> variable_time;
qi::rule<Iterator, osmoh::Time(), space_type> extended_time;
qi::rule<Iterator, osmoh::Time(), space_type> time;
qi::rule<Iterator, osmoh::TimeSpan(), space_type> timespan;
qi::rule<Iterator, osmoh::TTimeSpans(), space_type> main;
qi::rule<Iterator, osmoh::Timespan(), space_type> timespan;
qi::rule<Iterator, osmoh::TTimespans(), space_type> main;
class validate_timespan_impl
{
public:
template <typename T>
struct result { typedef bool type; };
// class validate_timespan_impl
// {
// public:
// template <typename T>
// struct result { typedef bool type; };
bool operator() (osmoh::TimeSpan const & ts) const
{
using boost::posix_time::ptime;
using boost::posix_time::time_duration;
using boost::posix_time::hours;
using boost::posix_time::minutes;
using boost::posix_time::time_period;
// bool operator() (osmoh::TimeSpan const & ts) const
// {
// using boost::posix_time::ptime;
// using boost::posix_time::time_duration;
// using boost::posix_time::hours;
// using boost::posix_time::minutes;
// using boost::posix_time::time_period;
bool result = true;
if (ts.period.flags)
{
time_period tp = osmoh::make_time_period(boost::gregorian::day_clock::local_day(), ts);
result = (tp.length() >= time_duration(ts.period.hours, ts.period.minutes, 0 /* seconds */));
}
// bool result = true;
// if (ts.period.flags)
// {
// time_period tp = osmoh::make_time_period(boost::gregorian::day_clock::local_day(), ts);
// result = (tp.length() >= time_duration(ts.period.hours, ts.period.minutes, 0 /* seconds */));
// }
return result;
}
};
// return result;
// }
// };
public:
time_selector() : time_selector::base_type(main)
@ -423,39 +428,29 @@ class time_selector : public qi::grammar<Iterator, osmoh::TTimeSpans(), space_ty
using qi::_a;
using qi::_val;
using qi::lit;
using qi::_pass;
// using qi::_pass;
using charset::char_;
using boost::phoenix::at_c;
using boost::phoenix::bind;
using boost::phoenix::construct;
phx::function<validate_timespan_impl> const validate_timespan = validate_timespan_impl();
// phx::function<validate_timespan_impl> const validate_timespan = validate_timespan_impl();
hour_minutes = hours[at_c<0>(_val) = _1, at_c<2>(_val) |= osmoh::Time::eHours]
|| (((lit(':') | lit("") | lit('.')) >> minutes[at_c<1>(_val) = _1,
at_c<2>(_val) |= osmoh::Time::eMinutes])
^ charset::no_case[lit('h') | lit("hs") | lit("hrs") | lit("uhr")]
^ (charset::no_case[lit("am")][_a = 0] | charset::no_case[lit("pm")][_a = 1])
[phx::if_(at_c<0>(_val) <= 12)[at_c<0>(_val) += (12 * _a)]])
hour_minutes = (hours >> lit(':') >> minutes)[bind(&osmoh::Time::SetHours, _val, _1),
bind(&osmoh::Time::SetMinutes, _val, _2)]
;
extended_hour_minutes = exthours[at_c<0>(_val) = _1, at_c<2>(_val) |= osmoh::Time::eHours]
|| (((lit(':') | lit("") | lit('.')) >> minutes[at_c<1>(_val) = _1,
at_c<2>(_val) |= osmoh::Time::eMinutes])
^ charset::no_case[lit('h') | lit("hs") | lit("hrs") | lit("uhr")]
^ (charset::no_case[lit("am")][_a = 0] | charset::no_case[lit("pm")][_a = 1])
[phx::if_(at_c<0>(_val) <= 12)[at_c<0>(_val) += (12 * _a)]])
extended_hour_minutes = (exthours >> lit(':') >> minutes)[bind(&osmoh::Time::SetHours, _val, _1),
bind(&osmoh::Time::SetMinutes, _val, _2)]
;
variable_time =
(lit('(')
>> charset::no_case[event][at_c<2>(_val) |= _1]
>> (
char_('+')[at_c<2>(_val) |= osmoh::Time::ePlus]
| char_('-')[at_c<2>(_val) |= osmoh::Time::eMinus]
)
>> hour_minutes[at_c<2>(_1) |= at_c<2>(_val), _val = _1]
>> charset::no_case[event][bind(&osmoh::Time::SetEvent, _val, _1)]
>> (char_('+') | char_('-')[_val = -_val])
>> hour_minutes
>> lit(')')
)
| charset::no_case[event][at_c<2>(_val) |= _1]
| charset::no_case[event][bind(&osmoh::Time::SetEvent, _val, _1)]
;
extended_time %= extended_hour_minutes | variable_time;
@ -464,21 +459,34 @@ class time_selector : public qi::grammar<Iterator, osmoh::TTimeSpans(), space_ty
timespan =
(time >> dash >> extended_time >> L'/' >> hour_minutes)
[at_c<0>(_val) = _1, at_c<1>(_val) = _2, at_c<2>(_val) |= osmoh::Time::eExt,
at_c<3>(_val) = _3]
[bind(&osmoh::Timespan::SetStart, _val, _1),
bind(&osmoh::Timespan::SetEnd, _val, _2),
bind(&osmoh::Timespan::SetPeriod, _val, _3)]
| (time >> dash >> extended_time >> L'/' >> minutes)
[at_c<0>(_val) = _1, at_c<1>(_val) = _2, at_c<2>(_val) |= osmoh::Time::eExt,
at_c<1>(at_c<3>(_val)) = _3, at_c<2>(at_c<3>(_val)) = osmoh::Time::eMinutes]
[bind(&osmoh::Timespan::SetStart, _val, _1),
bind(&osmoh::Timespan::SetEnd, _val, _2),
bind(&osmoh::Timespan::SetPeriod, _val, _3)]
// bind(&osmoh::Timespan::SetPeriod, _val, construct<osmoh::Time::TMinutes>(_3))]
| (time >> dash >> extended_time >> char_(L'+'))
[at_c<0>(_val) = _1, at_c<1>(_val) = _2, at_c<2>(_val) |= osmoh::Time::ePlus]
[bind(&osmoh::Timespan::SetStart, _val, _1),
bind(&osmoh::Timespan::SetEnd, _val, _2),
bind(&osmoh::Timespan::SetPlus, _val, true)]
| (time >> dash >> extended_time)
[at_c<0>(_val) = _1, at_c<1>(_val) = _2]
[bind(&osmoh::Timespan::SetStart, _val, _1),
bind(&osmoh::Timespan::SetEnd, _val, _2)]
| (time >> char_(L'+'))
[at_c<0>(_val) = _1, at_c<2>(_val) |= osmoh::Time::ePlus]
| time [at_c<0>(_val) = _1]
[bind(&osmoh::Timespan::SetStart, _val, _1),
bind(&osmoh::Timespan::SetPlus, _val, true)]
| time[bind(&osmoh::Timespan::SetStart, _val, _1)]
;
main %= timespan[_pass = validate_timespan(_1)] % ',';
// main %= timespan[_pass = validate_timespan(_1)] % ',';
main %= timespan % ',';
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(timespan);
@ -489,130 +497,130 @@ class time_selector : public qi::grammar<Iterator, osmoh::TTimeSpans(), space_ty
}
};
template <typename Iterator>
class selectors : public qi::grammar<Iterator, osmoh::TimeRule(), space_type>
{
protected:
weekday_selector<Iterator> weekday_selector;
time_selector<Iterator> time_selector;
year_selector<Iterator> year_selector;
month_selector<Iterator> month_selector;
week_selector<Iterator> week_selector;
// template <typename Iterator>
// class selectors : public qi::grammar<Iterator, osmoh::TimeRule(), space_type>
// {
// protected:
// weekday_selector<Iterator> weekday_selector;
// time_selector<Iterator> time_selector;
// year_selector<Iterator> year_selector;
// month_selector<Iterator> month_selector;
// week_selector<Iterator> week_selector;
qi::rule<Iterator, std::string(), space_type> comment;
qi::rule<Iterator, osmoh::TimeRule(), space_type> small_range_selectors;
qi::rule<Iterator, space_type> wide_range_selectors;
qi::rule<Iterator, osmoh::TimeRule(), space_type> main;
public:
selectors() : selectors::base_type(main)
{
using qi::_1;
using qi::_val;
using qi::lit;
using qi::lexeme;
using charset::char_;
using boost::phoenix::at_c;
using osmoh::State;
// qi::rule<Iterator, std::string(), space_type> comment;
// qi::rule<Iterator, osmoh::TimeRule(), space_type> small_range_selectors;
// qi::rule<Iterator, space_type> wide_range_selectors;
// qi::rule<Iterator, osmoh::TimeRule(), space_type> main;
// public:
// selectors() : selectors::base_type(main)
// {
// using qi::_1;
// using qi::_val;
// using qi::lit;
// using qi::lexeme;
// using charset::char_;
// using boost::phoenix::at_c;
// using osmoh::State;
comment %= lexeme['"' >> +(char_ - '"') >> '"'];
wide_range_selectors = -year_selector >> -month_selector >> -week_selector >> -lit(':') | (comment >> ':');
small_range_selectors = -weekday_selector[at_c<0>(_val) = _1] >> -( lit("24/7") | time_selector[at_c<1>(_val) = _1]);
// comment %= lexeme['"' >> +(char_ - '"') >> '"'];
// wide_range_selectors = -year_selector >> -month_selector >> -week_selector >> -lit(':') | (comment >> ':');
// small_range_selectors = -weekday_selector[at_c<0>(_val) = _1] >> -( lit("24/7") | time_selector[at_c<1>(_val) = _1]);
main =
(
lit(L"24/7")
| lit(L"24時間営業")
| lit(L"7/24")
| lit(L"24時間")
| charset::no_case[lit(L"daily 24/7")]
| charset::no_case[lit(L"24 hours")]
| charset::no_case[lit(L"24 horas")]
| charset::no_case[lit(L"круглосуточно")]
| charset::no_case[lit(L"24 часа")]
| charset::no_case[lit(L"24 hrs")]
| charset::no_case[lit(L"nonstop")]
| charset::no_case[lit(L"24hrs")]
| charset::no_case[lit(L"open 24 hours")]
| charset::no_case[lit(L"24 stunden")]
)[at_c<0>(at_c<2>(_val)) = State::eOpen]
| (-wide_range_selectors >> small_range_selectors[_val = _1, at_c<0>(at_c<2>(_val)) = State::eOpen])
;
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(small_range_selectors);
BOOST_SPIRIT_DEBUG_NODE(wide_range_selectors);
}
};
// main =
// (
// lit(L"24/7")
// | lit(L"24時間営業")
// | lit(L"7/24")
// | lit(L"24時間")
// | charset::no_case[lit(L"daily 24/7")]
// | charset::no_case[lit(L"24 hours")]
// | charset::no_case[lit(L"24 horas")]
// | charset::no_case[lit(L"круглосуточно")]
// | charset::no_case[lit(L"24 часа")]
// | charset::no_case[lit(L"24 hrs")]
// | charset::no_case[lit(L"nonstop")]
// | charset::no_case[lit(L"24hrs")]
// | charset::no_case[lit(L"open 24 hours")]
// | charset::no_case[lit(L"24 stunden")]
// )[at_c<0>(at_c<2>(_val)) = State::eOpen]
// | (-wide_range_selectors >> small_range_selectors[_val = _1, at_c<0>(at_c<2>(_val)) = State::eOpen])
// ;
// BOOST_SPIRIT_DEBUG_NODE(main);
// BOOST_SPIRIT_DEBUG_NODE(small_range_selectors);
// BOOST_SPIRIT_DEBUG_NODE(wide_range_selectors);
// }
// };
template <typename Iterator>
class time_domain : public qi::grammar<Iterator, osmoh::TTimeRules(), space_type, qi::locals<qi::rule<Iterator, space_type>*>>
{
protected:
selectors<Iterator> selector_sequence;
// template <typename Iterator>
// class time_domain : public qi::grammar<Iterator, osmoh::TTimeRules(), space_type, qi::locals<qi::rule<Iterator, space_type>*>>
// {
// protected:
// selectors<Iterator> selector_sequence;
qi::rule<Iterator, std::string(), space_type> comment;
qi::rule<Iterator, space_type> separator;
qi::rule<Iterator, space_type> base_separator;
qi::rule<Iterator, osmoh::TimeRule(), space_type> rule_sequence;
qi::rule<Iterator, osmoh::State(), space_type> rule_modifier;
qi::rule<Iterator, osmoh::TTimeRules(), space_type, qi::locals<qi::rule<Iterator, space_type>*>> main;
// qi::rule<Iterator, std::string(), space_type> comment;
// qi::rule<Iterator, space_type> separator;
// qi::rule<Iterator, space_type> base_separator;
// qi::rule<Iterator, osmoh::TimeRule(), space_type> rule_sequence;
// qi::rule<Iterator, osmoh::State(), space_type> rule_modifier;
// qi::rule<Iterator, osmoh::TTimeRules(), space_type, qi::locals<qi::rule<Iterator, space_type>*>> main;
public:
time_domain() : time_domain::base_type(main)
{
using qi::lit;
using qi::lexeme;
using qi::_1;
using qi::_a;
using qi::_val;
using charset::char_;
using boost::phoenix::at_c;
using qi::lazy;
using qi::eps;
using osmoh::State;
// public:
// time_domain() : time_domain::base_type(main)
// {
// using qi::lit;
// using qi::lexeme;
// using qi::_1;
// using qi::_a;
// using qi::_val;
// using charset::char_;
// using boost::phoenix::at_c;
// using qi::lazy;
// using qi::eps;
// using osmoh::State;
comment %= lexeme['"' >> +(char_ - '"') >> '"'] | lexeme['(' >> +(char_ - ')') >> ')'];
base_separator = lit(';') | lit("||");
separator = lit(';') | lit("||") | lit(',');
// comment %= lexeme['"' >> +(char_ - '"') >> '"'] | lexeme['(' >> +(char_ - ')') >> ')'];
// base_separator = lit(';') | lit("||");
// separator = lit(';') | lit("||") | lit(',');
rule_modifier =
(charset::no_case[lit("open")][at_c<0>(_val) = State::eOpen] >> -comment[at_c<1>(_val) = _1])
| ((charset::no_case[lit("closed") | lit("off")])[at_c<0>(_val) = State::eClosed] >> -comment[at_c<1>(_val) = _1])
| (charset::no_case[lit("unknown")][at_c<0>(_val) = State::eUnknown] >> -comment[at_c<1>(_val) = _1])
| comment[at_c<0>(_val) = State::eUnknown, at_c<1>(_val) = _1]
;
// rule_modifier =
// (charset::no_case[lit("open")][at_c<0>(_val) = State::eOpen] >> -comment[at_c<1>(_val) = _1])
// | ((charset::no_case[lit("closed") | lit("off")])[at_c<0>(_val) = State::eClosed] >> -comment[at_c<1>(_val) = _1])
// | (charset::no_case[lit("unknown")][at_c<0>(_val) = State::eUnknown] >> -comment[at_c<1>(_val) = _1])
// | comment[at_c<0>(_val) = State::eUnknown, at_c<1>(_val) = _1]
// ;
rule_sequence = selector_sequence[_val = _1]
>> -rule_modifier[at_c<2>(_val) = _1, at_c<3>(_val) = 1];
// rule_sequence = selector_sequence[_val = _1]
// >> -rule_modifier[at_c<2>(_val) = _1, at_c<3>(_val) = 1];
main %= -(lit("opening_hours") >> lit('='))
>> rule_sequence[_a = phx::val(&base_separator),
phx::if_(at_c<3>(_1) || phx::size(at_c<1>(_1)))[_a = phx::val(&separator)]] % lazy(*_a);
// main %= -(lit("opening_hours") >> lit('='))
// >> rule_sequence[_a = phx::val(&base_separator),
// phx::if_(at_c<3>(_1) || phx::size(at_c<1>(_1)))[_a = phx::val(&separator)]] % lazy(*_a);
BOOST_SPIRIT_DEBUG_NODE(main);
BOOST_SPIRIT_DEBUG_NODE(rule_sequence);
BOOST_SPIRIT_DEBUG_NODE(rule_modifier);
}
};
// BOOST_SPIRIT_DEBUG_NODE(main);
// BOOST_SPIRIT_DEBUG_NODE(rule_sequence);
// BOOST_SPIRIT_DEBUG_NODE(rule_modifier);
// }
// };
template <typename Iterator>
inline bool parse_timerange(Iterator first, Iterator last, osmoh::TTimeRules & context)
{
using qi::phrase_parse;
using charset::space;
// template <typename Iterator>
// inline bool parse_timerange(Iterator first, Iterator last, osmoh::TTimeRules & context)
// {
// using qi::phrase_parse;
// using charset::space;
time_domain<Iterator> time_domain;
// time_domain<Iterator> time_domain;
bool r = phrase_parse(
first, /* start iterator */
last, /* end iterator */
time_domain, /* the parser */
space, /* the skip-parser */
context /* result storage */
);
// bool r = phrase_parse(
// first, /* start iterator */
// last, /* end iterator */
// time_domain, /* the parser */
// space, /* the skip-parser */
// context /* result storage */
// );
if (first != last) // fail if we did not get a full match
return false;
return r;
}
// if (first != last) // fail if we did not get a full match
// return false;
// return r;
// }
} // namespace parsing
} // namespace osmoh

View file

@ -26,270 +26,486 @@
#include <iomanip>
#include <ios>
#include <cstdlib>
#include <codecvt>
namespace osmoh
{
std::ostream & operator << (std::ostream & s, Time const & t)
Time::Time(TMinutes const minutes)
{
bool event = (t.flags & Time::eSunrise) || (t.flags & Time::eSunset);
if (event)
s << ((t.flags & Time::eSunrise) ? "sunrise" : "sunset") << " (";
std::ios_base::fmtflags sf = s.flags();
if (t.flags & (Time::ePlus | Time::eMinus))
s << ((t.flags & Time::ePlus) ? "+" : "-");
if (t.flags & Time::eHours)
s << std::setw(2) << std::setfill('0') << (int)t.hours;
if (t.flags & Time::eMinutes)
s << ":" << std::setw(2) << std::setfill('0') << (int)t.minutes;
s.flags(sf);
if (event)
s << ")";
return s;
SetMinutes(minutes);
}
std::ostream & operator << (std::ostream & s, TimeSpan const & span)
{
s << span.from;
if (span.to.flags)
s << '-' << span.to;
if (span.flags == Time::ePlus)
s << "...";
if (span.flags == Time::eExt)
s << '/' << span.period;
// Time::Time(THours const hours, TMinutes const minutes) { }
// Time::Time(EEvent const event, THours const hours = 0, TMinutes const minutes = 0) { }
return s;
Time::THours::rep Time::GetHoursCount() const
{
return GetHours().count();
}
std::ostream & operator << (std::ostream & s, Weekday const & w)
Time::TMinutes::rep Time::GetMinutesCount() const
{
static char const * wdays[] = {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"};
static uint8_t const kDaysInWeek = 7;
static uint8_t const kWeeksInMonth = 5;
for (size_t i = 0; i < kDaysInWeek; ++i)
{
if (w.weekdays & (1 << i))
{
if (w.weekdays & ((1 << i) - 1))
s << ',';
s << wdays[i];
}
}
if (w.nth)
{
s << "[";
uint8_t a = w.nth & 0xFF;
for (size_t i = 0; i < kWeeksInMonth; ++i)
{
if (a & (1 << i))
{
if (a & ((1 << i) - 1))
s << ',';
s << (i + 1);
}
}
a = (w.nth >> 8) & 0xFF;
for (size_t i = 0; i < kWeeksInMonth; ++i)
{
if (a & (1 << i))
{
if (a & ((1 << i) - 1))
s << ',';
s << '-' << (i + 1);
}
}
s << "]";
}
if (w.offset)
s << ' ' << w.offset << " day(s)";
return s;
return GetMinutes().count();
}
std::ostream & operator << (std::ostream & s, State const & w)
Time::THours Time::GetHours() const
{
static char const * st[] = {"unknown", "closed", "open"};
s << ' ' << st[w.state] << " " << w.comment;
return s;
if (IsEvent())
return GetEventTime().GetHours();
else if (IsEventOffset())
return (GetEventTime() - *this).GetHours();
return std::chrono::duration_cast<THours>(m_duration);
}
std::ostream & operator << (std::ostream & s, TimeRule const & w)
Time::TMinutes Time::GetMinutes() const
{
for (auto const & e : w.weekdays)
s << e;
if (!w.weekdays.empty() && !w.timespan.empty())
s << ' ';
for (auto const & e : w.timespan)
s << e;
std::cout << "Weekdays size " << w.weekdays.size() <<
" Timespan size " << w.timespan.size() << std::endl;
return s << w.state;
}
} // namespace osmoh
namespace
{
bool check_timespan(osmoh::TimeSpan const &ts, boost::gregorian::date const & d, boost::posix_time::ptime const & p)
{
using boost::gregorian::days;
using boost::posix_time::ptime;
using boost::posix_time::hours;
using boost::posix_time::minutes;
using boost::posix_time::time_period;
time_period tp1 = osmoh::make_time_period(d-days(1), ts);
time_period tp2 = osmoh::make_time_period(d, ts);
/* very useful in debug */
// std::cout << ts << "\t" << tp1 << "(" << p << ")" << (tp1.contains(p) ? " hit" : " miss") << std::endl;
// std::cout << ts << "\t" << tp2 << "(" << p << ")" << (tp2.contains(p) ? " hit" : " miss") << std::endl;
return tp1.contains(p) || tp2.contains(p);
if (IsEvent())
return GetEventTime().GetMinutes();
else if (IsEventOffset())
return (GetEventTime() - *this).GetMinutes();
return std::chrono::duration_cast<TMinutes>(m_duration) - GetHours();
}
bool check_weekday(osmoh::Weekday const & wd, boost::gregorian::date const & d)
void Time::SetHours(THours const hours)
{
using namespace boost::gregorian;
bool hit = false;
typedef nth_day_of_the_week_in_month nth_dow;
if (wd.nth)
{
for (uint8_t i = 0; (wd.weekdays & (0xFF ^ ((1 << i) - 1))); ++i)
{
if (!(wd.weekdays & (1 << i)))
continue;
uint8_t a = wd.nth & 0xFF;
for (size_t j = 0; (a & (0xFF ^ ((1 << j) - 1))); ++j)
{
if (a & (1 << j))
{
nth_dow ndm(nth_dow::week_num(j + 1), nth_dow::day_of_week_type((i + 1 == 7) ? 0 : (i + 1)), d.month());
hit |= (d == ndm.get_date(d.year()));
}
}
a = (wd.nth >> 8) & 0xFF;
for (size_t j = 0; (a & (0xFF ^ ((1 << j) - 1))); ++j)
{
if (a & (1 << j))
{
last_day_of_the_week_in_month lwdm(nth_dow::day_of_week_type((i + 1 == 7) ? 0 : (i + 1)), d.month());
hit |= (d == ((lwdm.get_date(d.year()) - weeks(j)) + days(wd.offset)));
}
}
}
}
else
{
for (uint8_t i = 0; (wd.weekdays & (0xFF ^ ((1 << i) - 1))); ++i)
{
if (!(wd.weekdays & (1 << i)))
continue;
hit |= (d.day_of_week() == ((i + 1 == 7) ? 0 : (i + 1)));
}
}
/* very useful in debug */
// std::cout << d.day_of_week() << " " << d << " --> " << wd << (hit ? " hit" : " miss") << std::endl;
return hit;
m_state |= eHaveHours | eHaveMinutes;
m_duration += hours;
}
bool check_rule(osmoh::TimeRule const & r, std::tm const & stm,
std::ostream * hitcontext = nullptr)
void Time::SetMinutes(TMinutes const minutes)
{
bool next = false;
// check 24/7
if (r.weekdays.empty() && r.timespan.empty() && r.state.state == osmoh::State::eOpen)
return true;
boost::gregorian::date date = boost::gregorian::date_from_tm(stm);
boost::posix_time::ptime pt = boost::posix_time::ptime_from_tm(stm);
next = r.weekdays.empty();
for (auto const & wd : r.weekdays)
{
if (check_weekday(wd, date))
{
if (hitcontext)
*hitcontext << wd << " ";
next = true;
}
}
if (!next)
return next;
next = r.timespan.empty();
for (auto const & ts : r.timespan)
{
if (check_timespan(ts, date, pt))
{
if (hitcontext)
*hitcontext << ts << " ";
next = true;
}
}
return next && !(r.timespan.empty() && r.weekdays.empty());
}
} // anonymouse namespace
OSMTimeRange OSMTimeRange::FromString(std::string const & rules)
{
OSMTimeRange timeRange;
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; // could not work on android
std::wstring src = converter.from_bytes(rules); // rules should be wstring
timeRange.m_valid = osmoh::parsing::parse_timerange(src.begin(), src.end(), timeRange.m_rules);
return timeRange;
m_state |= eHaveMinutes;
if (minutes > THours(1))
m_state |= eHaveHours;
m_duration += minutes;
}
OSMTimeRange & OSMTimeRange::UpdateState(time_t timestamp)
void Time::SetEvent(EEvent const event)
{
std::tm stm = *localtime(&timestamp);
m_event = event;
}
osmoh::State::EState true_state[3][3] = {
{osmoh::State::eUnknown, osmoh::State::eClosed, osmoh::State::eOpen},
{osmoh::State::eClosed , osmoh::State::eClosed, osmoh::State::eOpen},
{osmoh::State::eOpen , osmoh::State::eClosed, osmoh::State::eOpen}
};
bool Time::IsEvent() const
{
return m_event != EEvent::eNotEvent;
}
osmoh::State::EState false_state[3][3] = {
{osmoh::State::eUnknown, osmoh::State::eOpen , osmoh::State::eClosed},
{osmoh::State::eClosed , osmoh::State::eClosed , osmoh::State::eClosed},
{osmoh::State::eOpen , osmoh::State::eOpen , osmoh::State::eOpen}
};
bool Time::IsEventOffset() const
{
return IsEvent() && m_state != eIsNotTime;
}
m_state = osmoh::State::eUnknown;
m_comment = std::string();
bool Time::IsHoursMinutes() const
{
return !IsEvent() && (m_state & (eHaveHours | eHaveMinutes));
}
for (auto const & el : m_rules)
{
bool hit = false;
if ((hit = check_rule(el, stm)))
{
m_state = true_state[m_state][el.state.state];
m_comment = el.state.comment;
}
else
{
m_state = false_state[m_state][el.state.state];
}
/* very useful in debug */
// char const * st[] = {"unknown", "closed", "open"};
// std::cout << "-[" << hit << "]-------------------[" << el << "]: " << st[m_state] << "--------------------" << std::endl;
}
bool Time::IsMinutes() const
{
return !IsEvent() && ((m_state & eHaveMinutes) && !(m_state & eHaveHours));
}
bool Time::IsTime() const
{
return IsHoursMinutes() || IsEvent();
}
bool Time::HasValue() const
{
return IsEvent() || IsTime() || IsMinutes();
}
Time & Time::operator-(Time const & time)
{
m_duration -= time.m_duration;
return *this;
}
OSMTimeRange & OSMTimeRange::UpdateState(std::string const & timestr, char const * timefmt)
Time & Time::operator-()
{
std::tm when = {};
std::stringstream ss(timestr);
ss >> std::get_time(&when, timefmt);
return UpdateState(std::mktime(&when));
m_duration = -m_duration;
return *this;
}
Time Time::GetEventTime() const {return {};}; // TODO(mgsergio): get real time
std::ostream & operator<<(std::ostream & ost, Time::EEvent const event)
{
switch(event)
{
case Time::EEvent::eNotEvent:
ost << "NotEvent";
break;
case Time::EEvent::eSunrise:
ost << "sunrise";
break;
case Time::EEvent::eSunset:
ost << "sunset";
break;
case Time::EEvent::eDawn:
ost << "dawn";
break;
case Time::EEvent::eDusk:
ost << "dusk";
break;
}
return ost;
}
std::ostream & operator<<(std::ostream & ost, Time const & time)
{
std::ios_base::fmtflags backupFlags = ost.flags();
if (!time.IsTime() && !time.IsEvent())
{
ost << "hh:mm";
return ost;
}
auto const minutes = time.GetMinutesCount();
auto const hours = time.GetHoursCount();
if (time.IsEvent())
{
if (time.IsEventOffset())
{
ost << '(' << hours;
if (hours < 0)
ost << '-';
else
ost << '+';
ost << std::setw(2) << std::setfill('0')
<< std::abs(hours)
<< ':' << std::setw(2)
<< std::abs(minutes) << ')';
}
ost << time.GetEvent();
}
if (time.IsMinutes())
{
ost << std::setw(2) << std::setfill('0')
<< std::abs(minutes);
}
else
{
ost << std::setw(2) << std::setfill('0')
<< std::abs(hours)
<< ':' << std::setw(2)
<< std::abs(minutes);
}
ost.flags(backupFlags);
return ost;
}
bool Timespan::IsOpen() const
{
return !m_end.HasValue();
}
bool Timespan::HasPlus() const
{
return m_plus;
}
bool Timespan::HasPeriod() const
{
return m_period.HasValue();
}
Time const & Timespan::GetStart() const
{
return m_start;
}
Time const & Timespan::GetEnd() const
{
return m_end;
}
Time const & Timespan::GetPeriod() const
{
return m_period;
}
void Timespan::SetStart(Time const & start)
{
m_start = start;
}
void Timespan::SetEnd(Time const & end)
{
m_end = end;
}
void Timespan::SetPeriod(Time const & period)
{
m_period = period;
}
void Timespan::SetPlus(bool const plus)
{
m_plus = plus;
}
bool Timespan::IsValid() const
{
return false; // TODO(mgsergio): implement validator
}
std::ostream & operator<<(std::ostream & ost, Timespan const & span)
{
ost << span.GetStart();
if (!span.IsOpen())
{
ost << '-' << span.GetEnd();
if (span.HasPeriod())
ost << '/' << span.GetPeriod();
}
if (span.HasPlus())
ost << '+';
return ost;
}
std::ostream & operator<<(std::ostream & ost, osmoh::TTimespans const & timespans)
{
auto it = begin(timespans);
ost << *it++;
while(it != end(timespans))
{
ost << ',' << *it++;
}
return ost;
}
// std::ostream & operator << (std::ostream & s, Weekday const & w)
// {
// static char const * wdays[] = {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"};
// static uint8_t const kDaysInWeek = 7;
// static uint8_t const kWeeksInMonth = 5;
// for (size_t i = 0; i < kDaysInWeek; ++i)
// {
// if (w.weekdays & (1 << i))
// {
// if (w.weekdays & ((1 << i) - 1))
// s << ',';
// s << wdays[i];
// }
// }
// if (w.nth)
// {
// s << "[";
// uint8_t a = w.nth & 0xFF;
// for (size_t i = 0; i < kWeeksInMonth; ++i)
// {
// if (a & (1 << i))
// {
// if (a & ((1 << i) - 1))
// s << ',';
// s << (i + 1);
// }
// }
// a = (w.nth >> 8) & 0xFF;
// for (size_t i = 0; i < kWeeksInMonth; ++i)
// {
// if (a & (1 << i))
// {
// if (a & ((1 << i) - 1))
// s << ',';
// s << '-' << (i + 1);
// }
// }
// s << "]";
// }
// if (w.offset)
// s << ' ' << w.offset << " day(s)";
// return s;
// }
// std::ostream & operator << (std::ostream & s, State const & w)
// {
// static char const * st[] = {"unknown", "closed", "open"};
// s << ' ' << st[w.state] << " " << w.comment;
// return s;
// }
// std::ostream & operator << (std::ostream & s, TimeRule const & w)
// {
// for (auto const & e : w.weekdays)
// s << e;
// if (!w.weekdays.empty() && !w.timespan.empty())
// s << ' ';
// for (auto const & e : w.timespan)
// s << e;
// std::cout << "Weekdays size " << w.weekdays.size() <<
// " Timespan size " << w.timespan.size() << std::endl;
// return s << w.state;
// }
} // namespace osmoh
// namespace
// {
// bool check_timespan(osmoh::TimeSpan const &ts, boost::gregorian::date const & d, boost::posix_time::ptime const & p)
// {
// using boost::gregorian::days;
// using boost::posix_time::ptime;
// using boost::posix_time::hours;
// using boost::posix_time::minutes;
// using boost::posix_time::time_period;
// time_period tp1 = osmoh::make_time_period(d-days(1), ts);
// time_period tp2 = osmoh::make_time_period(d, ts);
// /* very useful in debug */
// // std::cout << ts << "\t" << tp1 << "(" << p << ")" << (tp1.contains(p) ? " hit" : " miss") << std::endl;
// // std::cout << ts << "\t" << tp2 << "(" << p << ")" << (tp2.contains(p) ? " hit" : " miss") << std::endl;
// return tp1.contains(p) || tp2.contains(p);
// }
// bool check_weekday(osmoh::Weekday const & wd, boost::gregorian::date const & d)
// {
// using namespace boost::gregorian;
// bool hit = false;
// typedef nth_day_of_the_week_in_month nth_dow;
// if (wd.nth)
// {
// for (uint8_t i = 0; (wd.weekdays & (0xFF ^ ((1 << i) - 1))); ++i)
// {
// if (!(wd.weekdays & (1 << i)))
// continue;
// uint8_t a = wd.nth & 0xFF;
// for (size_t j = 0; (a & (0xFF ^ ((1 << j) - 1))); ++j)
// {
// if (a & (1 << j))
// {
// nth_dow ndm(nth_dow::week_num(j + 1), nth_dow::day_of_week_type((i + 1 == 7) ? 0 : (i + 1)), d.month());
// hit |= (d == ndm.get_date(d.year()));
// }
// }
// a = (wd.nth >> 8) & 0xFF;
// for (size_t j = 0; (a & (0xFF ^ ((1 << j) - 1))); ++j)
// {
// if (a & (1 << j))
// {
// last_day_of_the_week_in_month lwdm(nth_dow::day_of_week_type((i + 1 == 7) ? 0 : (i + 1)), d.month());
// hit |= (d == ((lwdm.get_date(d.year()) - weeks(j)) + days(wd.offset)));
// }
// }
// }
// }
// else
// {
// for (uint8_t i = 0; (wd.weekdays & (0xFF ^ ((1 << i) - 1))); ++i)
// {
// if (!(wd.weekdays & (1 << i)))
// continue;
// hit |= (d.day_of_week() == ((i + 1 == 7) ? 0 : (i + 1)));
// }
// }
// /* very useful in debug */
// // std::cout << d.day_of_week() << " " << d << " --> " << wd << (hit ? " hit" : " miss") << std::endl;
// return hit;
// }
// bool check_rule(osmoh::TimeRule const & r, std::tm const & stm,
// std::ostream * hitcontext = nullptr)
// {
// bool next = false;
// // check 24/7
// if (r.weekdays.empty() && r.timespan.empty() && r.state.state == osmoh::State::eOpen)
// return true;
// boost::gregorian::date date = boost::gregorian::date_from_tm(stm);
// boost::posix_time::ptime pt = boost::posix_time::ptime_from_tm(stm);
// next = r.weekdays.empty();
// for (auto const & wd : r.weekdays)
// {
// if (check_weekday(wd, date))
// {
// if (hitcontext)
// *hitcontext << wd << " ";
// next = true;
// }
// }
// if (!next)
// return next;
// next = r.timespan.empty();
// for (auto const & ts : r.timespan)
// {
// if (check_timespan(ts, date, pt))
// {
// if (hitcontext)
// *hitcontext << ts << " ";
// next = true;
// }
// }
// return next && !(r.timespan.empty() && r.weekdays.empty());
// }
// } // anonymouse namespace
// OSMTimeRange OSMTimeRange::FromString(std::string const & rules)
// {
// OSMTimeRange timeRange;
// std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; // could not work on android
// std::wstring src = converter.from_bytes(rules); // rules should be wstring
// timeRange.m_valid = osmoh::parsing::parse_timerange(src.begin(), src.end(), timeRange.m_rules);
// return timeRange;
// }
// OSMTimeRange & OSMTimeRange::UpdateState(time_t timestamp)
// {
// std::tm stm = *localtime(&timestamp);
// osmoh::State::EState true_state[3][3] = {
// {osmoh::State::eUnknown, osmoh::State::eClosed, osmoh::State::eOpen},
// {osmoh::State::eClosed , osmoh::State::eClosed, osmoh::State::eOpen},
// {osmoh::State::eOpen , osmoh::State::eClosed, osmoh::State::eOpen}
// };
// osmoh::State::EState false_state[3][3] = {
// {osmoh::State::eUnknown, osmoh::State::eOpen , osmoh::State::eClosed},
// {osmoh::State::eClosed , osmoh::State::eClosed , osmoh::State::eClosed},
// {osmoh::State::eOpen , osmoh::State::eOpen , osmoh::State::eOpen}
// };
// m_state = osmoh::State::eUnknown;
// m_comment = std::string();
// for (auto const & el : m_rules)
// {
// bool hit = false;
// if ((hit = check_rule(el, stm)))
// {
// m_state = true_state[m_state][el.state.state];
// m_comment = el.state.comment;
// }
// else
// {
// m_state = false_state[m_state][el.state.state];
// }
// /* very useful in debug */
// // char const * st[] = {"unknown", "closed", "open"};
// // std::cout << "-[" << hit << "]-------------------[" << el << "]: " << st[m_state] << "--------------------" << std::endl;
// }
// return *this;
// }
// OSMTimeRange & OSMTimeRange::UpdateState(std::string const & timestr, char const * timefmt)
// {
// std::tm when = {};
// std::stringstream ss(timestr);
// ss >> std::get_time(&when, timefmt);
// return UpdateState(std::mktime(&when));
// }

View file

@ -27,123 +27,237 @@
#include <string>
#include <vector>
#include <iostream>
#include <chrono>
#include <type_traits>
namespace osmoh
{
class Weekday;
class TimeSpan;
class Timespan;
class TimeRule;
using TWeekdays = std::vector<Weekday>;
using TTimeSpans = std::vector<TimeSpan>;
using TTimeRules = std::vector<TimeRule>;
using TTimespans = std::vector<Timespan>;
class Time
{
public:
enum EFlags
enum EState
{
eNone = 0,
eHours = 1,
eMinutes = 2,
ePlus = 4,
eMinus = 8,
eExt = 16,
eSunrise = 32,
eSunset = 64
eIsNotTime = 0,
eHaveHours = 1,
eHaveMinutes = 2,
};
uint8_t hours;
uint8_t minutes;
uint8_t flags;
Time() : hours(0), minutes(0), flags(eNone) {}
Time & Hours(uint8_t h) { hours = h; flags |= eHours; return *this; }
Time & Minutes(uint8_t m) { minutes = m; flags |= eMinutes; return *this; }
Time & Sunset() { flags = eSunset; return *this; }
Time & Sunrise() { flags = eSunrise; return *this; }
std::string ToString() const;
friend std::ostream & operator << (std::ostream & s, Time const & t);
};
class TimeSpan
{
public:
Time from;
Time to;
uint8_t flags;
Time period;
TimeSpan() : flags(Time::eNone) {}
std::string ToString() const;
friend std::ostream & operator << (std::ostream & s, TimeSpan const & span);
};
class Weekday
{
public:
uint8_t weekdays;
uint16_t nth;
int32_t offset;
Weekday() : weekdays(0), nth(0), offset(0) {}
std::string ToString() const;
friend std::ostream & operator << (std::ostream & s, Weekday const & w);
};
class State
{
public:
enum EState {
eUnknown = 0,
eClosed = 1,
eOpen = 2
enum class EEvent
{
eNotEvent,
eDawn,
eSunrise,
eSunset,
eDusk
};
uint8_t state;
std::string comment;
using THours = std::chrono::hours;
using TMinutes = std::chrono::minutes;
State() : state(eUnknown) {}
};
class TimeRule
{
public:
TWeekdays weekdays;
TTimeSpans timespan; // TODO(mgsergio) rename to timespans
State state;
uint8_t int_flags = 0;
Time() = default;
Time(Time const &) = default;
Time(TMinutes const minutes);
Time(THours const hours, TMinutes const minutes);
Time(EEvent const event);
friend std::ostream & operator <<(std::ostream & s, TimeRule const & r);
};
} // namespace osmoh
THours::rep GetHoursCount() const;
TMinutes::rep GetMinutesCount() const;
class OSMTimeRange
{
public:
OSMTimeRange() = default;
THours GetHours() const;
TMinutes GetMinutes() const;
bool IsValid() const { return m_valid; }
bool IsOpen() const { return m_state == osmoh::State::eOpen; }
bool IsClosed() const { return m_state == osmoh::State::eClosed; }
bool IsUnknown() const { return m_state == osmoh::State::eUnknown; }
std::string const & Comment() const { return m_comment; }
void SetHours(THours const hours);
void SetMinutes(TMinutes const minutes);
OSMTimeRange & UpdateState(time_t timestamp);
OSMTimeRange & UpdateState(std::string const & timestr,
char const * timefmt="%d-%m-%Y %R");
EEvent GetEvent() const {return m_event;}
void SetEvent(EEvent const event);
std::string ToString() const;
bool IsEvent() const;
bool IsEventOffset() const;
bool IsHoursMinutes() const;
bool IsMinutes() const;
bool IsTime() const;
bool HasValue() const;
static OSMTimeRange FromString(std::string const & rules);
Time & operator-(Time const & time);
Time & operator-();
private:
bool m_valid{false};
osmoh::State::EState m_state{osmoh::State::eUnknown};
Time GetEventTime() const;
osmoh::TTimeRules m_rules;
std::string m_comment;
private:
EEvent m_event{EEvent::eNotEvent};
TMinutes m_duration{TMinutes::zero()};
std::underlying_type<EState>::type m_state{EState::eIsNotTime};
};
inline constexpr Time::THours operator ""_h(unsigned long long h)
{
return Time::THours(h);
}
inline constexpr Time::TMinutes operator ""_min(unsigned long long m)
{
return Time::TMinutes(m);
}
std::ostream & operator<<(std::ostream & ost, Time::EEvent const event);
std::ostream & operator<<(std::ostream & ost, Time const & time);
class Timespan
{
public:
Timespan() = default;
Timespan(Timespan const &) = default;
Timespan(Time const & start, bool plus = false);
Timespan(Time const & start, Time const & end, bool plus = false);
Timespan(Time const & start, Time const & end, Time const & period);
bool IsOpen() const;
bool HasPlus() const;
bool HasPeriod() const;
Time const & GetStart() const;
Time const & GetEnd() const;
Time const & GetPeriod() const;
void SetStart(Time const & start);
void SetEnd(Time const & end);
void SetPeriod(Time const & period);
void SetPlus(bool const plus);
bool IsValid() const;
private:
Time m_start;
Time m_end;
Time m_period;
bool m_plus{false};
};
std::ostream & operator<<(std::ostream & ost, Timespan const & span);
std::ostream & operator<<(std::ostream & ost, osmoh::TTimespans const & timespans);
} // namespace osmoh
// class Weekday
// {
// public:
// uint8_t weekdays;
// uint16_t nth;
// int32_t offset;
// Weekday() : weekdays(0), nth(0), offset(0) {}
// std::string ToString() const;
// friend std::ostream & operator << (std::ostream & s, Weekday const & w);
// };
// class State
// {
// public:
// enum EState {
// eUnknown = 0,
// eClosed = 1,
// eOpen = 2
// };
// uint8_t state;
// std::string comment;
// State() : state(eUnknown) {}
// };
// class TimeRule
// {
// public:
// TWeekdays weekdays;
// TTimeSpans timespan; // TODO(mgsergio) rename to timespans
// State state;
// uint8_t int_flags = 0;
// friend std::ostream & operator <<(std::ostream & s, TimeRule const & r);
// };
// } // namespace osmoh
// class OSMTimeRange
// {
// public:
// OSMTimeRange() = default;
// bool IsValid() const { return m_valid; }
// bool IsOpen() const { return m_state == osmoh::State::eOpen; }
// bool IsClosed() const { return m_state == osmoh::State::eClosed; }
// bool IsUnknown() const { return m_state == osmoh::State::eUnknown; }
// std::string const & Comment() const { return m_comment; }
// OSMTimeRange & UpdateState(time_t timestamp);
// OSMTimeRange & UpdateState(std::string const & timestr,
// char const * timefmt="%d-%m-%Y %R");
// std::string ToString() const;
// static OSMTimeRange FromString(std::string const & rules);
// private:
// bool m_valid{false};
// osmoh::State::EState m_state{osmoh::State::eUnknown};
// osmoh::TTimeRules m_rules;
// std::string m_comment;
// };
/// Trash
// class TimeEx
// {
// public:
// enum EFlags
// {
// eNone = 0,
// eHours = 1,
// eMinutes = 2,
// ePlus = 4,
// eMinus = 8,
// eExt = 16,
// eSunrise = 32,
// eSunset = 64
// };
// uint8_t hours;
// uint8_t minutes;
// uint8_t flags;
// Time() : hours(0), minutes(0), flags(eNone) {}
// Time & Hours(uint8_t h) { hours = h; flags |= eHours; return *this; }
// Time & Minutes(uint8_t m) { minutes = m; flags |= eMinutes; return *this; }
// Time & Sunset() { flags = eSunset; return *this; }
// Time & Sunrise() { flags = eSunrise; return *this; }
// std::string ToString() const;
// friend std::ostream & operator << (std::ostream & s, Time const & t);
// };
// class TimeSpanEx
// {
// public:
// Time from;
// Time to;
// uint8_t flags;
// Time period;
// TimeSpan() : flags(Time::eNone) {}
// std::string ToString() const;
// friend std::ostream & operator << (std::ostream & s, TimeSpan const & span);
// };