diff --git a/feature_list/feature_list.cpp b/feature_list/feature_list.cpp index 77afd7cd6..a8d357912 100644 --- a/feature_list/feature_list.cpp +++ b/feature_list/feature_list.cpp @@ -267,6 +267,8 @@ public: string const denomination(meta.Get(feature::Metadata::FMD_DENOMINATION)); string const wheelchair(GetWheelchairType(f)); string const opening_hours(meta.Get(feature::Metadata::FMD_OPEN_HOURS)); + string const check_date(meta.Get(feature::Metadata::FMD_CHECK_DATE)); + string const check_date_opening_hours(meta.Get(feature::Metadata::FMD_CHECK_DATE_OPEN_HOURS)); string const wikipedia(meta.Get(feature::Metadata::FMD_WIKIPEDIA)); string const wikimedia_commons(meta.Get(feature::Metadata::FMD_WIKIMEDIA_COMMONS)); string const panoramax(meta.Get(feature::Metadata::FMD_PANORAMAX)); @@ -277,7 +279,7 @@ public: vector columns = { osmId, uid, lat, lon, mwmName, category, name, std::string(city), addrStreet, addrHouse, phone, website, stars, std::string(metaOperator), internet, - denomination, wheelchair, opening_hours, wikipedia, floor, fee, atm, contact_facebook, + denomination, wheelchair, opening_hours, check_date, check_date_opening_hours, wikipedia, floor, fee, atm, contact_facebook, contact_instagram, contact_twitter, contact_vk, contact_line, contact_fediverse, contact_bluesky, wikimedia_commons, panoramax}; AppendNames(f, columns); @@ -290,7 +292,7 @@ void PrintHeader() vector columns = {"id", "old_id", "lat", "lon", "mwm", "category", "name", "city", "street", "house", "phone", "website", "cuisines", "stars", "operator", - "internet", "denomination", "wheelchair", "opening_hours", "wikipedia", + "internet", "denomination", "wheelchair", "opening_hours", "check_date", "check_date_opening_hours", "wikipedia", "floor", "fee", "atm", "contact_facebook", "contact_instagram", "contact_twitter", "contact_vk", "contact_line", "contact_fediverse", "contact_bluesky", "wikimedia_commons", "panoramax"}; // Append all supported name languages in order. diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 1f4f689e0..7ad81cb71 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -148,6 +148,28 @@ std::string MetadataTagProcessorImpl::ValidateAndFormat_opening_hours(std::strin return v; } +std::string MetadataTagProcessorImpl::ValidateAndFormat_date(std::string const & v) +{ + // Check if the date is in the format YYYY-MM-DD, and that it parses to a valid date. + std::regex const dateRegex(R"(^(\d{4})-(\d{2})-(\d{2})$)"); + std::smatch match; + if (std::regex_match(v, match, dateRegex)) + { + int year = std::stoi(match[1]); + int month = std::stoi(match[2]); + int day = std::stoi(match[3]); + + std::tm tm = {}; + std::istringstream ss(v); + ss >> std::get_time(&tm, "%Y-%m-%d"); + if (!ss.fail() && tm.tm_year + 1900 == year && tm.tm_mon + 1 == month && tm.tm_mday == day) + return v; + } + + LOG(LDEBUG, ("Invalid check_date tag value:", v)); + return {}; +} + std::string MetadataTagProcessorImpl::ValidateAndFormat_ele(std::string const & v) const { if (IsNoNameNoAddressBuilding(m_params)) @@ -532,10 +554,24 @@ void MetadataTagProcessor::operator()(std::string const & k, std::string const & if (!Metadata::TypeFromString(k, mdType)) return; + auto const & types = m_params.m_types; + std::string valid; switch (mdType) { case Metadata::FMD_OPEN_HOURS: valid = ValidateAndFormat_opening_hours(v); break; + case Metadata::FMD_CHECK_DATE: + if (ftypes::IsCheckDateChecker::Instance()(types)) + valid = ValidateAndFormat_date(v); + else + return; + break; + case Metadata::FMD_CHECK_DATE_OPEN_HOURS: + if (ftypes::IsCheckDateChecker::Instance()(types)) + valid = ValidateAndFormat_date(v); + else + return; + break; case Metadata::FMD_FAX_NUMBER: // The same validator as for phone. case Metadata::FMD_PHONE_NUMBER: valid = ValidateAndFormat_phone(v); break; case Metadata::FMD_STARS: valid = ValidateAndFormat_stars(v); break; diff --git a/generator/osm2meta.hpp b/generator/osm2meta.hpp index 2e3834912..f9bd112ab 100644 --- a/generator/osm2meta.hpp +++ b/generator/osm2meta.hpp @@ -15,6 +15,7 @@ struct MetadataTagProcessorImpl static std::string ValidateAndFormat_url(std::string const & v) ; static std::string ValidateAndFormat_phone(std::string const & v) ; static std::string ValidateAndFormat_opening_hours(std::string const & v) ; + static std::string ValidateAndFormat_date(std::string const & v) ; std::string ValidateAndFormat_ele(std::string const & v) const; static std::string ValidateAndFormat_destination(std::string const & v) ; static std::string ValidateAndFormat_local_ref(std::string const & v) ; diff --git a/indexer/feature_meta.cpp b/indexer/feature_meta.cpp index 7108856ed..cb4ebdcc1 100644 --- a/indexer/feature_meta.cpp +++ b/indexer/feature_meta.cpp @@ -75,6 +75,10 @@ bool Metadata::TypeFromString(string_view k, Metadata::EType & outType) { if (k == "opening_hours") outType = Metadata::FMD_OPEN_HOURS; + else if (k == "check_date" || k == "survey:date") + outType = Metadata::FMD_CHECK_DATE; + else if (k == "check_date:opening_hours") + outType = Metadata::FMD_CHECK_DATE_OPEN_HOURS; else if (k == "phone" || k == "contact:phone" || k == "contact:mobile" || k == "mobile") outType = Metadata::FMD_PHONE_NUMBER; else if (k == "fax" || k == "contact:fax") @@ -237,6 +241,8 @@ string ToString(Metadata::EType type) { case Metadata::FMD_CUISINE: return "cuisine"; case Metadata::FMD_OPEN_HOURS: return "opening_hours"; + case Metadata::FMD_CHECK_DATE: return "check_date"; + case Metadata::FMD_CHECK_DATE_OPEN_HOURS: return "check_date:opening_hours"; case Metadata::FMD_PHONE_NUMBER: return "phone"; case Metadata::FMD_FAX_NUMBER: return "fax"; case Metadata::FMD_STARS: return "stars"; diff --git a/indexer/feature_meta.hpp b/indexer/feature_meta.hpp index a5bd21fe9..1d765f938 100644 --- a/indexer/feature_meta.hpp +++ b/indexer/feature_meta.hpp @@ -158,6 +158,8 @@ public: FMD_CONTACT_FEDIVERSE = 50, FMD_CONTACT_BLUESKY = 51, FMD_PANORAMAX = 52, + FMD_CHECK_DATE = 53, + FMD_CHECK_DATE_OPEN_HOURS = 54, FMD_COUNT }; diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp index 50cb56634..b968b2179 100644 --- a/indexer/ftypes_matcher.cpp +++ b/indexer/ftypes_matcher.cpp @@ -500,6 +500,14 @@ IsAmenityChecker::IsAmenityChecker() : BaseChecker(1 /* level */) m_types.push_back(classif().GetTypeByPath({"amenity"})); } +IsCheckDateChecker::IsCheckDateChecker() : BaseChecker(1 /* level */) +{ + Classificator const & c = classif(); + for (auto const * path : {"amenity", "shop", "leisure", "tourism", "craft", + "emergency", "healthcare", "office"}) + m_types.push_back(c.GetTypeByPath({path})); +} + AttractionsChecker::AttractionsChecker() : BaseChecker(2 /* level */) { base::StringIL const primaryAttractionTypes[] = { diff --git a/indexer/ftypes_matcher.hpp b/indexer/ftypes_matcher.hpp index c4ea6c25f..ea639000e 100644 --- a/indexer/ftypes_matcher.hpp +++ b/indexer/ftypes_matcher.hpp @@ -319,6 +319,15 @@ public: uint32_t GetType() const { return m_types[0]; } }; +class IsCheckDateChecker : public BaseChecker +{ + IsCheckDateChecker(); +public: + DECLARE_CHECKER_INSTANCE(IsCheckDateChecker); + + uint32_t GetType() const { return m_types[0]; } +}; + class AttractionsChecker : public BaseChecker { size_t m_additionalTypesStart;