From 92488eecf9252426e2a968e62fb101c51c305f0f Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Thu, 1 Jan 2026 21:21:56 +0100 Subject: [PATCH 01/23] Date-Date operator overload --- src/util/DateYearDuration.cpp | 103 ++++++++++++++++++++++++++++++++++ src/util/DateYearDuration.h | 6 ++ 2 files changed, 109 insertions(+) diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index ce234ceba7..fbe34b1bbc 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -341,3 +341,106 @@ std::optional DateYearOrDuration::convertToXsdDate( return DateYearOrDuration( Date(date.getYear(), date.getMonth(), date.getDay())); } + +// _____________________________________________________________________________ +DateYearOrDuration DateYearOrDuration::operator-( + const DateYearOrDuration& rhs) { + // TODO: also support hours, minutes and seconds + if (isDate() && rhs.isDate()) { + // Date - Date = Duration | getting time between the two Dates + + // First Attempt + const Date& ownDate = getDateUnchecked(); + const Date& otherDate = rhs.getDateUnchecked(); + int yearsPassed = ownDate.getYear() - otherDate.getYear(); + int monthsPassed = ownDate.getMonth() - otherDate.getMonth(); + int daysPassed = ownDate.getDay() - otherDate.getDay(); + // TODO What happens in Schaltjahren? + daysPassed = daysPassed + (monthsPassed * 31) + (yearsPassed * 365); + + // Second Attempt + // Getting the dates + int ownYear = ownDate.getYear(); + int otherYear = otherDate.getYear(); + int ownMonth = ownDate.getMonth(); + int otherMonth = otherDate.getMonth(); + int ownDay = ownDate.getDay(); + int otherDay = otherDate.getDay(); + + // Counting the days passed. + daysPassed = 0; + while (!((ownYear == otherYear) && (ownMonth == otherMonth) && + (ownDay == otherDay))) { + daysPassed++; + // TODO: store this in a separate function + // TODO: handle Schaltjahre + if ((otherMonth == 12) && (otherDay == 31)) { + // jump to Jan 1 of next year + otherYear++; + otherMonth = 1; + otherDay = 1; + continue; + } + + if ((otherMonth == 2) && (otherDay == 28)) { + // special case: february month jump + otherMonth++; + otherDay = 1; + continue; + } + + if (otherDay == 30 + 1 * (((otherMonth <= 7) && (otherMonth % 2 == 1)) || + ((otherMonth >= 8) && otherMonth % 2 == 0))) { + // normal month jump + otherMonth++; + otherDay = 1; + continue; + } + } + return DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, daysPassed)); + } + + if (isDayTimeDuration() && rhs.isDayTimeDuration()) { + // Duration - Duration = Duration | getting new duration that is + // rhs.duration-time smaller return; + } + + if (isDate() && rhs.isDayTimeDuration()) { + // Date - Duration = Date | getting new Date from rhs.duration-time earlier + // return; + } + + if (isDayTimeDuration() && rhs.isDate()) { + // Duration - Date | not implemented + // return; + } + + // no viable subtraction + throw std::invalid_argument("No Subtraction possible!"); + + /* + if (getType() != rhs.getType()) { + // No possible Subtraction. + throw std::invalid_argument("To subtract the two objects, they need to have + the same type."); + } + // switch case actually on type of both objects + switch (getType()) { + case Type::DateTime: { + break; + } + case Type::Date: { + const Date& date1 = getDate(); + const Date& date2 = rhs.getDate(); + break; + } + case Type::YearMonth: { + break; + } + case Type::Year: { + break; + } + } + */ +} diff --git a/src/util/DateYearDuration.h b/src/util/DateYearDuration.h index 49f6a5dbdd..424884ecf7 100644 --- a/src/util/DateYearDuration.h +++ b/src/util/DateYearDuration.h @@ -205,6 +205,12 @@ class DateYearOrDuration { // std::nullopt. static std::optional convertToXsdDate( const DateYearOrDuration& dateValue); + + // Changes/Addition + //____________________________________________________________________________ + // Subtraction of two DateYearOrDuration Objects. + // Result should be used (nodiscard). + [[nodiscard]] DateYearOrDuration operator-(const DateYearOrDuration& rhs); }; #ifdef QLEVER_CPP_17 static_assert(std::is_default_constructible_v); From 50b6665aa4e964f99b424111520351dace9ca706 Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Wed, 7 Jan 2026 12:32:19 +0100 Subject: [PATCH 02/23] ValueGetter for NumericOrDate and extended Subtract Expression --- .../sparqlExpressions/NaryExpressionImpl.h | 37 ++++++++++++++++++ .../NumericBinaryExpressions.cpp | 39 ++++++++++++++++++- .../SparqlExpressionValueGetters.cpp | 29 ++++++++++++++ .../SparqlExpressionValueGetters.h | 18 +++++++++ src/util/DateYearDuration.cpp | 6 ++- src/util/DateYearDuration.h | 3 +- 6 files changed, 127 insertions(+), 5 deletions(-) diff --git a/src/engine/sparqlExpressions/NaryExpressionImpl.h b/src/engine/sparqlExpressions/NaryExpressionImpl.h index 2cd433de10..c73a3b5551 100644 --- a/src/engine/sparqlExpressions/NaryExpressionImpl.h +++ b/src/engine/sparqlExpressions/NaryExpressionImpl.h @@ -125,6 +125,43 @@ struct MakeNumericExpression { } }; +// Same as above, just added DateYearOrDuration. +// Takes a `Function` that takes and returns numeric values (integral or +// floating point) or dates and converts it to a function, that takes the same +// arguments and returns the same result, but the arguments and the return type +// are the `NumericOrDate` variant. +template +struct MakeNumericOrDateExpression { + template + Id operator()(const Args&... args) const { + CPP_assert((concepts::same_as, NumericOrDate> && ...)); + auto visitor = [](const auto&... t) { + if constexpr ((... || + std::is_same_v>)) { + return Id::makeUndefined(); + } else if constexpr ((... && std::is_same_v>)) { + // Operation containing Date can only work with other dates, not with a + // numeric value. + return makeFromDate(Function{}(t...)); + } else if constexpr ((... && + (std::is_same_v> || + std::is_same_v>))) { + // We need to guarantee that the result of Function is of a numeric type + // TODO: this is problematic because it is dedicated to NumericValue and + // not NumericOrDate + return makeNumericId(Function{}(t...)); + } else { + // Other combinations are not defined + return Id::makeUndefined(); + } + }; + return std::visit(visitor, args...); + } +}; + // Two short aliases to make the instantiations more readable. template using FV = FunctionAndValueGetters; diff --git a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp index 0ff110f6fc..236c73b9cf 100644 --- a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp +++ b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp @@ -40,8 +40,43 @@ NARY_EXPRESSION(DivideExpressionByZeroIsNan, 2, using Add = MakeNumericExpression>; NARY_EXPRESSION(AddExpression, 2, FV); -using Subtract = MakeNumericExpression>; -NARY_EXPRESSION(SubtractExpression, 2, FV); +// using Subtract = MakeNumericExpression>; +// NARY_EXPRESSION(SubtractExpression, 2, FV); +// _____________________________________________________________________________ +// Subtract. +struct SubtractImpl { + template + NumericOrDate operator()(L lhs, R rhs) const { + using T1 = std::decay_t; + using T2 = std::decay_t; + + if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { + return NumericOrDate{lhs - rhs}; + } else if constexpr (std::is_same_v) { + return NumericOrDate{lhs - static_cast(rhs)}; + } + } else if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { + return NumericOrDate{static_cast(lhs) - rhs}; + } else if constexpr (std::is_same_v) { + return NumericOrDate{lhs - rhs}; + } + } else if constexpr (std::is_same_v && + std::is_same_v) { + // Using - operator implementation in DateYearOrDuration. + return NumericOrDate{lhs - rhs}; + } + // For all other operations returning notNumeric + return NumericOrDate{NotNumeric{}}; + // TODO: NotNumeric ?? + // It is not allowed to use subtractionn between Date and NumericValue + // assert(std::is_same::value, "Unsupported Operation"); + } +}; +// TODO: MakeNumericOrDateExpression +using Subtract = MakeNumericOrDateExpression; +NARY_EXPRESSION(SubtractExpression, 2, FV); // _____________________________________________________________________________ // Power. diff --git a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp index da21e2a20c..5c2920cd7b 100644 --- a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp +++ b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp @@ -46,6 +46,35 @@ NumericValue NumericValueGetter::operator()( AD_FAIL(); } +// _____________________________________________________________________________ +NumericOrDate NumericOrDateGetter::operator()( + ValueId id, const sparqlExpression::EvaluationContext*) const { + switch (id.getDatatype()) { + case Datatype::Double: + return id.getDouble(); + case Datatype::Int: + return id.getInt(); + case Datatype::Bool: + // TODO Check in the specification what the correct behavior is + // here. They probably should be UNDEF as soon as we have conversion + // functions. + return static_cast(id.getBool()); + case Datatype::Undefined: + case Datatype::EncodedVal: + case Datatype::VocabIndex: + case Datatype::LocalVocabIndex: + case Datatype::TextRecordIndex: + case Datatype::WordVocabIndex: + return NotNumeric{}; + case Datatype::Date: + return id.getDate(); + case Datatype::GeoPoint: + case Datatype::BlankNodeIndex: + return NotNumeric{}; + } + AD_FAIL(); +} + // _____________________________________________________________________________ auto EffectiveBooleanValueGetter::operator()( ValueId id, const EvaluationContext* context) const -> Result { diff --git a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h index 8ff34450b8..f7deb74ad4 100644 --- a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h +++ b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h @@ -37,6 +37,11 @@ struct NotNumeric {}; // The input to an expression that expects a numeric value. using NumericValue = std::variant; using IntOrDouble = std::variant; +// The input to an expression that expects a numeric value or a date. +// Will be used in `NumericBinaryExpressions.cpp` to allow for subtraction of +// Dates. +using NumericOrDate = + std::variant; // Return type for `DatatypeValueGetter`. using LiteralOrString = @@ -102,6 +107,19 @@ struct NumericValueGetter : Mixin { NumericValue operator()(ValueId id, const EvaluationContext*) const; }; +// Return `NumericOrDate` which is then used as the input to numeric +// expressions. +struct NumericOrDateGetter : Mixin { + using Mixin::operator(); + // same as in NumericValueGetter + NumericOrDate operator()(const LiteralOrIri&, + const EvaluationContext*) const { + return NotNumeric{}; + } + + NumericOrDate operator()(ValueId id, const EvaluationContext*) const; +}; + /// Return the type exactly as it was passed in. /// This class is needed for the distinct calculation in the aggregates. struct ActualValueGetter { diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index fbe34b1bbc..3becd424ef 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -344,7 +344,7 @@ std::optional DateYearOrDuration::convertToXsdDate( // _____________________________________________________________________________ DateYearOrDuration DateYearOrDuration::operator-( - const DateYearOrDuration& rhs) { + const DateYearOrDuration& rhs) const { // TODO: also support hours, minutes and seconds if (isDate() && rhs.isDate()) { // Date - Date = Duration | getting time between the two Dates @@ -417,7 +417,9 @@ DateYearOrDuration DateYearOrDuration::operator-( } // no viable subtraction - throw std::invalid_argument("No Subtraction possible!"); + else { + throw std::invalid_argument("No Subtraction possible!"); + } /* if (getType() != rhs.getType()) { diff --git a/src/util/DateYearDuration.h b/src/util/DateYearDuration.h index 424884ecf7..0794850bbf 100644 --- a/src/util/DateYearDuration.h +++ b/src/util/DateYearDuration.h @@ -210,7 +210,8 @@ class DateYearOrDuration { //____________________________________________________________________________ // Subtraction of two DateYearOrDuration Objects. // Result should be used (nodiscard). - [[nodiscard]] DateYearOrDuration operator-(const DateYearOrDuration& rhs); + [[nodiscard]] DateYearOrDuration operator-( + const DateYearOrDuration& rhs) const; }; #ifdef QLEVER_CPP_17 static_assert(std::is_default_constructible_v); From c6dbba520a6a73211ca6912d6f3433b3903cc408 Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Wed, 7 Jan 2026 12:38:34 +0100 Subject: [PATCH 03/23] ValueGetter for NumericOrDate and extended Subtract Expression --- .../sparqlExpressions/NaryExpressionImpl.h | 37 ++++++++++++++++++ .../NumericBinaryExpressions.cpp | 39 ++++++++++++++++++- .../SparqlExpressionValueGetters.cpp | 29 ++++++++++++++ .../SparqlExpressionValueGetters.h | 18 +++++++++ src/util/DateYearDuration.cpp | 6 ++- src/util/DateYearDuration.h | 3 +- 6 files changed, 127 insertions(+), 5 deletions(-) diff --git a/src/engine/sparqlExpressions/NaryExpressionImpl.h b/src/engine/sparqlExpressions/NaryExpressionImpl.h index 2cd433de10..c73a3b5551 100644 --- a/src/engine/sparqlExpressions/NaryExpressionImpl.h +++ b/src/engine/sparqlExpressions/NaryExpressionImpl.h @@ -125,6 +125,43 @@ struct MakeNumericExpression { } }; +// Same as above, just added DateYearOrDuration. +// Takes a `Function` that takes and returns numeric values (integral or +// floating point) or dates and converts it to a function, that takes the same +// arguments and returns the same result, but the arguments and the return type +// are the `NumericOrDate` variant. +template +struct MakeNumericOrDateExpression { + template + Id operator()(const Args&... args) const { + CPP_assert((concepts::same_as, NumericOrDate> && ...)); + auto visitor = [](const auto&... t) { + if constexpr ((... || + std::is_same_v>)) { + return Id::makeUndefined(); + } else if constexpr ((... && std::is_same_v>)) { + // Operation containing Date can only work with other dates, not with a + // numeric value. + return makeFromDate(Function{}(t...)); + } else if constexpr ((... && + (std::is_same_v> || + std::is_same_v>))) { + // We need to guarantee that the result of Function is of a numeric type + // TODO: this is problematic because it is dedicated to NumericValue and + // not NumericOrDate + return makeNumericId(Function{}(t...)); + } else { + // Other combinations are not defined + return Id::makeUndefined(); + } + }; + return std::visit(visitor, args...); + } +}; + // Two short aliases to make the instantiations more readable. template using FV = FunctionAndValueGetters; diff --git a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp index 0ff110f6fc..236c73b9cf 100644 --- a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp +++ b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp @@ -40,8 +40,43 @@ NARY_EXPRESSION(DivideExpressionByZeroIsNan, 2, using Add = MakeNumericExpression>; NARY_EXPRESSION(AddExpression, 2, FV); -using Subtract = MakeNumericExpression>; -NARY_EXPRESSION(SubtractExpression, 2, FV); +// using Subtract = MakeNumericExpression>; +// NARY_EXPRESSION(SubtractExpression, 2, FV); +// _____________________________________________________________________________ +// Subtract. +struct SubtractImpl { + template + NumericOrDate operator()(L lhs, R rhs) const { + using T1 = std::decay_t; + using T2 = std::decay_t; + + if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { + return NumericOrDate{lhs - rhs}; + } else if constexpr (std::is_same_v) { + return NumericOrDate{lhs - static_cast(rhs)}; + } + } else if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { + return NumericOrDate{static_cast(lhs) - rhs}; + } else if constexpr (std::is_same_v) { + return NumericOrDate{lhs - rhs}; + } + } else if constexpr (std::is_same_v && + std::is_same_v) { + // Using - operator implementation in DateYearOrDuration. + return NumericOrDate{lhs - rhs}; + } + // For all other operations returning notNumeric + return NumericOrDate{NotNumeric{}}; + // TODO: NotNumeric ?? + // It is not allowed to use subtractionn between Date and NumericValue + // assert(std::is_same::value, "Unsupported Operation"); + } +}; +// TODO: MakeNumericOrDateExpression +using Subtract = MakeNumericOrDateExpression; +NARY_EXPRESSION(SubtractExpression, 2, FV); // _____________________________________________________________________________ // Power. diff --git a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp index da21e2a20c..5c2920cd7b 100644 --- a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp +++ b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp @@ -46,6 +46,35 @@ NumericValue NumericValueGetter::operator()( AD_FAIL(); } +// _____________________________________________________________________________ +NumericOrDate NumericOrDateGetter::operator()( + ValueId id, const sparqlExpression::EvaluationContext*) const { + switch (id.getDatatype()) { + case Datatype::Double: + return id.getDouble(); + case Datatype::Int: + return id.getInt(); + case Datatype::Bool: + // TODO Check in the specification what the correct behavior is + // here. They probably should be UNDEF as soon as we have conversion + // functions. + return static_cast(id.getBool()); + case Datatype::Undefined: + case Datatype::EncodedVal: + case Datatype::VocabIndex: + case Datatype::LocalVocabIndex: + case Datatype::TextRecordIndex: + case Datatype::WordVocabIndex: + return NotNumeric{}; + case Datatype::Date: + return id.getDate(); + case Datatype::GeoPoint: + case Datatype::BlankNodeIndex: + return NotNumeric{}; + } + AD_FAIL(); +} + // _____________________________________________________________________________ auto EffectiveBooleanValueGetter::operator()( ValueId id, const EvaluationContext* context) const -> Result { diff --git a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h index 8ff34450b8..f7deb74ad4 100644 --- a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h +++ b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h @@ -37,6 +37,11 @@ struct NotNumeric {}; // The input to an expression that expects a numeric value. using NumericValue = std::variant; using IntOrDouble = std::variant; +// The input to an expression that expects a numeric value or a date. +// Will be used in `NumericBinaryExpressions.cpp` to allow for subtraction of +// Dates. +using NumericOrDate = + std::variant; // Return type for `DatatypeValueGetter`. using LiteralOrString = @@ -102,6 +107,19 @@ struct NumericValueGetter : Mixin { NumericValue operator()(ValueId id, const EvaluationContext*) const; }; +// Return `NumericOrDate` which is then used as the input to numeric +// expressions. +struct NumericOrDateGetter : Mixin { + using Mixin::operator(); + // same as in NumericValueGetter + NumericOrDate operator()(const LiteralOrIri&, + const EvaluationContext*) const { + return NotNumeric{}; + } + + NumericOrDate operator()(ValueId id, const EvaluationContext*) const; +}; + /// Return the type exactly as it was passed in. /// This class is needed for the distinct calculation in the aggregates. struct ActualValueGetter { diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index fbe34b1bbc..3becd424ef 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -344,7 +344,7 @@ std::optional DateYearOrDuration::convertToXsdDate( // _____________________________________________________________________________ DateYearOrDuration DateYearOrDuration::operator-( - const DateYearOrDuration& rhs) { + const DateYearOrDuration& rhs) const { // TODO: also support hours, minutes and seconds if (isDate() && rhs.isDate()) { // Date - Date = Duration | getting time between the two Dates @@ -417,7 +417,9 @@ DateYearOrDuration DateYearOrDuration::operator-( } // no viable subtraction - throw std::invalid_argument("No Subtraction possible!"); + else { + throw std::invalid_argument("No Subtraction possible!"); + } /* if (getType() != rhs.getType()) { diff --git a/src/util/DateYearDuration.h b/src/util/DateYearDuration.h index 424884ecf7..0794850bbf 100644 --- a/src/util/DateYearDuration.h +++ b/src/util/DateYearDuration.h @@ -210,7 +210,8 @@ class DateYearOrDuration { //____________________________________________________________________________ // Subtraction of two DateYearOrDuration Objects. // Result should be used (nodiscard). - [[nodiscard]] DateYearOrDuration operator-(const DateYearOrDuration& rhs); + [[nodiscard]] DateYearOrDuration operator-( + const DateYearOrDuration& rhs) const; }; #ifdef QLEVER_CPP_17 static_assert(std::is_default_constructible_v); From b831b915e23940653fa6af07ba23c0b4e958ec57 Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Sat, 10 Jan 2026 21:58:11 +0100 Subject: [PATCH 04/23] Deleted MakeNumericOrDateExpression & now returning ValueId in SubtractImpl --- .../sparqlExpressions/NaryExpressionImpl.h | 37 ------------------- .../NumericBinaryExpressions.cpp | 22 +++++------ 2 files changed, 9 insertions(+), 50 deletions(-) diff --git a/src/engine/sparqlExpressions/NaryExpressionImpl.h b/src/engine/sparqlExpressions/NaryExpressionImpl.h index c73a3b5551..2cd433de10 100644 --- a/src/engine/sparqlExpressions/NaryExpressionImpl.h +++ b/src/engine/sparqlExpressions/NaryExpressionImpl.h @@ -125,43 +125,6 @@ struct MakeNumericExpression { } }; -// Same as above, just added DateYearOrDuration. -// Takes a `Function` that takes and returns numeric values (integral or -// floating point) or dates and converts it to a function, that takes the same -// arguments and returns the same result, but the arguments and the return type -// are the `NumericOrDate` variant. -template -struct MakeNumericOrDateExpression { - template - Id operator()(const Args&... args) const { - CPP_assert((concepts::same_as, NumericOrDate> && ...)); - auto visitor = [](const auto&... t) { - if constexpr ((... || - std::is_same_v>)) { - return Id::makeUndefined(); - } else if constexpr ((... && std::is_same_v>)) { - // Operation containing Date can only work with other dates, not with a - // numeric value. - return makeFromDate(Function{}(t...)); - } else if constexpr ((... && - (std::is_same_v> || - std::is_same_v>))) { - // We need to guarantee that the result of Function is of a numeric type - // TODO: this is problematic because it is dedicated to NumericValue and - // not NumericOrDate - return makeNumericId(Function{}(t...)); - } else { - // Other combinations are not defined - return Id::makeUndefined(); - } - }; - return std::visit(visitor, args...); - } -}; - // Two short aliases to make the instantiations more readable. template using FV = FunctionAndValueGetters; diff --git a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp index 236c73b9cf..978a1aba0f 100644 --- a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp +++ b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp @@ -46,37 +46,33 @@ NARY_EXPRESSION(AddExpression, 2, FV); // Subtract. struct SubtractImpl { template - NumericOrDate operator()(L lhs, R rhs) const { + ValueId operator()(L lhs, R rhs) const { using T1 = std::decay_t; using T2 = std::decay_t; if constexpr (std::is_same_v) { if constexpr (std::is_same_v) { - return NumericOrDate{lhs - rhs}; + return Id::makeFromDouble(lhs - rhs); } else if constexpr (std::is_same_v) { - return NumericOrDate{lhs - static_cast(rhs)}; + return Id::makeFromDouble(lhs - static_cast(rhs)); } } else if constexpr (std::is_same_v) { if constexpr (std::is_same_v) { - return NumericOrDate{static_cast(lhs) - rhs}; + return Id::makeFromDouble(tstatic_cast(lhs) - rhs); } else if constexpr (std::is_same_v) { - return NumericOrDate{lhs - rhs}; + return Id::makeFromInt(lhs - rhs); } } else if constexpr (std::is_same_v && std::is_same_v) { // Using - operator implementation in DateYearOrDuration. - return NumericOrDate{lhs - rhs}; + return Id::makeFromDate(lhs - rhs); } - // For all other operations returning notNumeric - return NumericOrDate{NotNumeric{}}; - // TODO: NotNumeric ?? + // For all other operations returning Undefined // It is not allowed to use subtractionn between Date and NumericValue - // assert(std::is_same::value, "Unsupported Operation"); + return Id::makeUndefined(); } }; -// TODO: MakeNumericOrDateExpression -using Subtract = MakeNumericOrDateExpression; -NARY_EXPRESSION(SubtractExpression, 2, FV); +NARY_EXPRESSION(SubtractExpression, 2, FV); // _____________________________________________________________________________ // Power. From 59a5d84c4154c0f86b612ebbc4a5aac6f82cd87e Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Tue, 13 Jan 2026 18:04:28 +0100 Subject: [PATCH 05/23] working subtraction for Date - Date; Time not supported yet --- src/util/DateYearDuration.cpp | 71 ++++++++++++++++++----------------- test/DateYearDurationTest.cpp | 64 +++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 34 deletions(-) diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index 3becd424ef..fc71f2b36a 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -343,34 +343,61 @@ std::optional DateYearOrDuration::convertToXsdDate( } // _____________________________________________________________________________ +#ifndef REDUCED_FEATURE_SET_FOR_CPP17 DateYearOrDuration DateYearOrDuration::operator-( const DateYearOrDuration& rhs) const { // TODO: also support hours, minutes and seconds if (isDate() && rhs.isDate()) { + // TODO: handle time as well // Date - Date = Duration | getting time between the two Dates + const Date& ownDate = getDateUnchecked(); + const Date& otherDate = rhs.getDateUnchecked(); + + auto date1 = + std::chrono::year_month_day{std::chrono::year(ownDate.getYear()) / + ownDate.getMonth() / ownDate.getDay()}; + auto date2 = + std::chrono::year_month_day{std::chrono::year(otherDate.getYear()) / + otherDate.getMonth() / otherDate.getDay()}; + + int daysPassed = + (std::chrono::sys_days{date1} - std::chrono::sys_days{date2}).count(); + + if (daysPassed < 0) { + daysPassed = abs(daysPassed); + } + + // Third Attempt + // std::chrono::sys_days{ End } - std::chrono::sys_days{ Start } + // const Date& ownDate = getDateUnchecked(); + // const Date& otherDate = rhs.getDateUnchecked(); + + // ownDate.get + // std::chrono::system_clock::from_time_t // First Attempt + /* const Date& ownDate = getDateUnchecked(); const Date& otherDate = rhs.getDateUnchecked(); - int yearsPassed = ownDate.getYear() - otherDate.getYear(); - int monthsPassed = ownDate.getMonth() - otherDate.getMonth(); - int daysPassed = ownDate.getDay() - otherDate.getDay(); - // TODO What happens in Schaltjahren? + int yearsPassed = abs(ownDate.getYear() - otherDate.getYear()); + int monthsPassed = abs(ownDate.getMonth() - otherDate.getMonth()); + int daysPassed = abs(ownDate.getDay() - otherDate.getDay()); daysPassed = daysPassed + (monthsPassed * 31) + (yearsPassed * 365); + */ // Second Attempt // Getting the dates - int ownYear = ownDate.getYear(); + /*int ownYear = ownDate.getYear(); int otherYear = otherDate.getYear(); int ownMonth = ownDate.getMonth(); int otherMonth = otherDate.getMonth(); int ownDay = ownDate.getDay(); - int otherDay = otherDate.getDay(); + int otherDay = otherDate.getDay();*/ // Counting the days passed. - daysPassed = 0; + /*daysPassed = 0; while (!((ownYear == otherYear) && (ownMonth == otherMonth) && - (ownDay == otherDay))) { + (ownDay == otherDay))) { daysPassed++; // TODO: store this in a separate function // TODO: handle Schaltjahre @@ -396,7 +423,7 @@ DateYearOrDuration DateYearOrDuration::operator-( otherDay = 1; continue; } - } + }*/ return DateYearOrDuration( DayTimeDuration(DayTimeDuration::Type::Positive, daysPassed)); } @@ -420,29 +447,5 @@ DateYearOrDuration DateYearOrDuration::operator-( else { throw std::invalid_argument("No Subtraction possible!"); } - - /* - if (getType() != rhs.getType()) { - // No possible Subtraction. - throw std::invalid_argument("To subtract the two objects, they need to have - the same type."); - } - // switch case actually on type of both objects - switch (getType()) { - case Type::DateTime: { - break; - } - case Type::Date: { - const Date& date1 = getDate(); - const Date& date2 = rhs.getDate(); - break; - } - case Type::YearMonth: { - break; - } - case Type::Year: { - break; - } - } - */ } +#endif diff --git a/test/DateYearDurationTest.cpp b/test/DateYearDurationTest.cpp index 3f92b1c1e2..6e61301712 100644 --- a/test/DateYearDurationTest.cpp +++ b/test/DateYearDurationTest.cpp @@ -575,3 +575,67 @@ TEST(DateYearOrDuration, Hashing) { ad_utility::HashSet set{d1, d2}; EXPECT_THAT(set, ::testing::UnorderedElementsAre(d1, d2)); } + +// _____________________________________________________________________________ +TEST(DateYearOrDuration, Subtraction) { + for (int i = 0; i < 10; ++i) { + auto year = yearGenerator(); + auto month = monthGenerator(); + auto day = dayGenerator(); + /*auto hour = hourGenerator(); + auto minute = minuteGenerator(); + auto second = secondGenerator(); + auto timeZone = timeZoneGenerator();*/ + + // Date date(year, month, day, hour, minute, second, timeZone); + Date date(year, month, day); + DateYearOrDuration date1(date); + + auto year2 = yearGenerator(); + auto month2 = monthGenerator(); + auto day2 = dayGenerator(); + /*auto hour2 = hourGenerator(); + auto minute2 = minuteGenerator(); + auto second2 = secondGenerator(); + auto timeZone2 = timeZoneGenerator();*/ + + // Date date_(year2, month2, day2, hour2, minute2, second2, timeZone2); + Date date_(year2, month2, day2); + DateYearOrDuration date2(date_); + + DateYearOrDuration zero_duration( + DayTimeDuration(DayTimeDuration::Type::Positive, 0)); + ASSERT_EQ(zero_duration, date1 - date1); + ASSERT_EQ(zero_duration, date2 - date2); + + DateYearOrDuration result = date1 - date2; + ASSERT_EQ(true, result.isDayTimeDuration()); + } + // hardcoded test + DateYearOrDuration test1 = DateYearOrDuration(Date(2012, 12, 24)); + DateYearOrDuration test2 = DateYearOrDuration(Date(2012, 12, 1)); + + DateYearOrDuration result = test1 - test2; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ( + DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, 23)), + result); + result = test2 - test1; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ( + DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, 23)), + result); + + test1 = DateYearOrDuration(Date(2012, 12, 24)); + test2 = DateYearOrDuration(Date(2010, 12, 24)); + result = test1 - test2; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ( + DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, 731)), + test1 - test2); + result = test2 - test1; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ( + DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, 731)), + result); +} From 38dad7b53fd3525de32240a23725dada1d47b49e Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Fri, 16 Jan 2026 13:42:49 +0100 Subject: [PATCH 06/23] Test and DateTime - DateTime operator overload --- src/util/DateYearDuration.cpp | 136 +++++++++++++++++++--------------- test/DateYearDurationTest.cpp | 71 +++++++++++++++--- 2 files changed, 137 insertions(+), 70 deletions(-) diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index fc71f2b36a..7d1022b585 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -344,6 +344,63 @@ std::optional DateYearOrDuration::convertToXsdDate( // _____________________________________________________________________________ #ifndef REDUCED_FEATURE_SET_FOR_CPP17 +void updatePassedTimes(const Date& date1, const Date& date2, int& daysPassed, + int& hoursPassed, int& minutesPassed, + double& secondsPassed) { + // helper function for Subtraction + // this function allows to swap the dates, if daysPassed was negative before + // applying abs. updating daysPassed, hoursPassed, minutesPassed, + // secondsPassed accordingly + if (date1.hasTime()) { + int hour1 = date1.getHour(); + int minute1 = date1.getMinute(); + double second1 = date1.getSecond(); + if (date2.hasTime()) { + int hour2 = date2.getHour(); + int minute2 = date2.getMinute(); + double second2 = date2.getSecond(); + if (hour1 < hour2) { + daysPassed--; // counted one day to much + hoursPassed = + 24 - (hour2 - hour1); // total hours of a day - difference + } else { + hoursPassed = (hour1 - hour2); + } + if (minute1 < minute2) { + hoursPassed--; // same as above just one level down + minutesPassed = 60 - (minute2 - minute1); + } else { + minutesPassed = (minute1 - minute2); + } + if (second1 < second2) { + minutesPassed--; + secondsPassed = 60 - (second2 - second1); + } else { + secondsPassed = (second1 - second2); + } + } else { + // if there is no time given, assume 00:00h 0seconds + hoursPassed = hour1; + minutesPassed = minute1; + secondsPassed = second1; + } + } else { + // date1 has no time, therefore we are assuming time 00:00:00 + if (date2.hasTime()) { + int hour2 = date2.getHour(); + int minute2 = date2.getMinute(); + double second2 = date2.getSecond(); + daysPassed--; + secondsPassed = 60.0 - second2; + minutesPassed = + 60 - + (minute2 + 1 * (secondsPassed > + 0.0)); // we add 1 because the seconds added a minute + hoursPassed = 24 - (hour2 + 1 * (minutesPassed > 0)); + } + } +} + DateYearOrDuration DateYearOrDuration::operator-( const DateYearOrDuration& rhs) const { // TODO: also support hours, minutes and seconds @@ -353,6 +410,7 @@ DateYearOrDuration DateYearOrDuration::operator-( const Date& ownDate = getDateUnchecked(); const Date& otherDate = rhs.getDateUnchecked(); + // Calculate number of days between the two Dates auto date1 = std::chrono::year_month_day{std::chrono::year(ownDate.getYear()) / ownDate.getMonth() / ownDate.getDay()}; @@ -362,70 +420,28 @@ DateYearOrDuration DateYearOrDuration::operator-( int daysPassed = (std::chrono::sys_days{date1} - std::chrono::sys_days{date2}).count(); + int hoursPassed = 0; + int minutesPassed = 0; + double secondsPassed = 0.0; + + bool isDaysPassedPos = true; if (daysPassed < 0) { + isDaysPassedPos = false; daysPassed = abs(daysPassed); } - - // Third Attempt - // std::chrono::sys_days{ End } - std::chrono::sys_days{ Start } - // const Date& ownDate = getDateUnchecked(); - // const Date& otherDate = rhs.getDateUnchecked(); - - // ownDate.get - // std::chrono::system_clock::from_time_t - - // First Attempt - /* - const Date& ownDate = getDateUnchecked(); - const Date& otherDate = rhs.getDateUnchecked(); - int yearsPassed = abs(ownDate.getYear() - otherDate.getYear()); - int monthsPassed = abs(ownDate.getMonth() - otherDate.getMonth()); - int daysPassed = abs(ownDate.getDay() - otherDate.getDay()); - daysPassed = daysPassed + (monthsPassed * 31) + (yearsPassed * 365); - */ - - // Second Attempt - // Getting the dates - /*int ownYear = ownDate.getYear(); - int otherYear = otherDate.getYear(); - int ownMonth = ownDate.getMonth(); - int otherMonth = otherDate.getMonth(); - int ownDay = ownDate.getDay(); - int otherDay = otherDate.getDay();*/ - - // Counting the days passed. - /*daysPassed = 0; - while (!((ownYear == otherYear) && (ownMonth == otherMonth) && - (ownDay == otherDay))) { - daysPassed++; - // TODO: store this in a separate function - // TODO: handle Schaltjahre - if ((otherMonth == 12) && (otherDay == 31)) { - // jump to Jan 1 of next year - otherYear++; - otherMonth = 1; - otherDay = 1; - continue; - } - - if ((otherMonth == 2) && (otherDay == 28)) { - // special case: february month jump - otherMonth++; - otherDay = 1; - continue; - } - - if (otherDay == 30 + 1 * (((otherMonth <= 7) && (otherMonth % 2 == 1)) || - ((otherMonth >= 8) && otherMonth % 2 == 0))) { - // normal month jump - otherMonth++; - otherDay = 1; - continue; - } - }*/ - return DateYearOrDuration( - DayTimeDuration(DayTimeDuration::Type::Positive, daysPassed)); + // Calculate time passed between the two Dates if at least one of them has a + // Time. + if (isDaysPassedPos) { + updatePassedTimes(ownDate, otherDate, daysPassed, hoursPassed, + minutesPassed, secondsPassed); + } else { + updatePassedTimes(otherDate, ownDate, daysPassed, hoursPassed, + minutesPassed, secondsPassed); + } + return DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, + daysPassed, hoursPassed, + minutesPassed, secondsPassed)); } if (isDayTimeDuration() && rhs.isDayTimeDuration()) { diff --git a/test/DateYearDurationTest.cpp b/test/DateYearDurationTest.cpp index 6e61301712..9bbbfc6c15 100644 --- a/test/DateYearDurationTest.cpp +++ b/test/DateYearDurationTest.cpp @@ -578,29 +578,28 @@ TEST(DateYearOrDuration, Hashing) { // _____________________________________________________________________________ TEST(DateYearOrDuration, Subtraction) { - for (int i = 0; i < 10; ++i) { + // OVERFLOW + /*for (int i = 0; i < 10; ++i) { auto year = yearGenerator(); auto month = monthGenerator(); auto day = dayGenerator(); - /*auto hour = hourGenerator(); + auto hour = hourGenerator(); auto minute = minuteGenerator(); auto second = secondGenerator(); - auto timeZone = timeZoneGenerator();*/ + auto timeZone = timeZoneGenerator(); - // Date date(year, month, day, hour, minute, second, timeZone); - Date date(year, month, day); + Date date(year, month, day, hour, minute, second, timeZone); DateYearOrDuration date1(date); auto year2 = yearGenerator(); auto month2 = monthGenerator(); auto day2 = dayGenerator(); - /*auto hour2 = hourGenerator(); + auto hour2 = hourGenerator(); auto minute2 = minuteGenerator(); auto second2 = secondGenerator(); - auto timeZone2 = timeZoneGenerator();*/ + auto timeZone2 = timeZoneGenerator(); - // Date date_(year2, month2, day2, hour2, minute2, second2, timeZone2); - Date date_(year2, month2, day2); + Date date_(year2, month2, day2, hour2, minute2, second2, timeZone2); DateYearOrDuration date2(date_); DateYearOrDuration zero_duration( @@ -610,8 +609,12 @@ TEST(DateYearOrDuration, Subtraction) { DateYearOrDuration result = date1 - date2; ASSERT_EQ(true, result.isDayTimeDuration()); - } + }*/ + // OVERFLOW + // hardcoded test + // ____________________________________________________________________________ + // Test for Date Subtraction DateYearOrDuration test1 = DateYearOrDuration(Date(2012, 12, 24)); DateYearOrDuration test2 = DateYearOrDuration(Date(2012, 12, 1)); @@ -638,4 +641,52 @@ TEST(DateYearOrDuration, Subtraction) { ASSERT_EQ( DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, 731)), result); + + test2 = DateYearOrDuration(Date(1979, 3, 13)); + result = test1 - test2; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 12340)), + result); + + test1 = DateYearOrDuration(Date(1868, 5, 16)); + result = test1 - test2; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 40477)), + result); + // ____________________________________________________________________________ + // Test for DateTime Subtraction + // DateTime - DateTime + DateYearOrDuration date1 = DateYearOrDuration(Date(2012, 12, 22, 12, 6, 12)); + DateYearOrDuration date2 = DateYearOrDuration(Date(2012, 12, 20, 15, 15, 59)); + // expected duration of 1d20h50min13sec + result = date1 - date2; + ASSERT_EQ(DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, + 1, 20, 50, 13)), + result); + result = date2 - date1; + ASSERT_EQ(DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, + 1, 20, 50, 13)), + result); + + date2 = DateYearOrDuration(Date(2010, 1, 13, 10, 32, 15)); + // expected duration of 1074d1h33min57sec + result = date1 - date2; + ASSERT_EQ(DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, + 1074, 1, 33, 57)), + result); + + // Date - DateTime + date1 = DateYearOrDuration(Date(2012, 12, 22)); + date2 = DateYearOrDuration(Date(2012, 12, 20, 13, 50, 59)); + // expected duration of 1d10h9min1sec + result = date1 - date2; + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 1, 10, 9, 1)), + result); + result = date2 - date1; + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 1, 10, 9, 1)), + result); } From 3698083ff25f281e06020dc441663f2075ecd9ae Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Fri, 16 Jan 2026 15:51:37 +0100 Subject: [PATCH 07/23] some small changes in comments --- src/util/DateYearDuration.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index 7d1022b585..9ee91d058d 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -403,10 +403,8 @@ void updatePassedTimes(const Date& date1, const Date& date2, int& daysPassed, DateYearOrDuration DateYearOrDuration::operator-( const DateYearOrDuration& rhs) const { - // TODO: also support hours, minutes and seconds if (isDate() && rhs.isDate()) { - // TODO: handle time as well - // Date - Date = Duration | getting time between the two Dates + // Date - Date => Duration | getting time between the two Dates const Date& ownDate = getDateUnchecked(); const Date& otherDate = rhs.getDateUnchecked(); @@ -445,18 +443,19 @@ DateYearOrDuration DateYearOrDuration::operator-( } if (isDayTimeDuration() && rhs.isDayTimeDuration()) { - // Duration - Duration = Duration | getting new duration that is + // Duration - Duration => Duration | getting new duration that is // rhs.duration-time smaller return; + // TODO: implement } if (isDate() && rhs.isDayTimeDuration()) { - // Date - Duration = Date | getting new Date from rhs.duration-time earlier + // Date - Duration => Date | getting new Date from rhs.duration-time earlier // return; + // TODO: implement } if (isDayTimeDuration() && rhs.isDate()) { // Duration - Date | not implemented - // return; } // no viable subtraction From 5f4a885ec3f748ce9947a2371dc188a81aa06824 Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Mon, 19 Jan 2026 15:42:21 +0100 Subject: [PATCH 08/23] debug output --- src/engine/sparqlExpressions/NumericBinaryExpressions.cpp | 2 ++ src/util/DateYearDuration.cpp | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp index 978a1aba0f..95ed6bdf08 100644 --- a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp +++ b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp @@ -65,10 +65,12 @@ struct SubtractImpl { } else if constexpr (std::is_same_v && std::is_same_v) { // Using - operator implementation in DateYearOrDuration. + AD_LOG_INFO << "Date" << std::endl; return Id::makeFromDate(lhs - rhs); } // For all other operations returning Undefined // It is not allowed to use subtractionn between Date and NumericValue + AD_LOG_INFO << "Undefined" << std::endl; return Id::makeUndefined(); } }; diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index 9ee91d058d..46be75a716 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -459,8 +459,6 @@ DateYearOrDuration DateYearOrDuration::operator-( } // no viable subtraction - else { - throw std::invalid_argument("No Subtraction possible!"); - } + throw std::invalid_argument("No Subtraction possible!"); } #endif From 435c21403d6838fd720f62d41220f6376688dcf1 Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Mon, 19 Jan 2026 16:53:20 +0100 Subject: [PATCH 09/23] Subtraction is now working for date1 - date2 with date1.year >= date2.year --- .../sparqlExpressions/NumericBinaryExpressions.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp index 95ed6bdf08..7e6fc98c3b 100644 --- a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp +++ b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp @@ -45,8 +45,14 @@ NARY_EXPRESSION(AddExpression, 2, FV); // _____________________________________________________________________________ // Subtract. struct SubtractImpl { - template - ValueId operator()(L lhs, R rhs) const { + ValueId operator()(NumericOrDate lhs, NumericOrDate rhs) const { + return std::visit(SubtractImpl{}, lhs, rhs); + } + + CPP_template(typename L, typename R)( + requires(!std::is_same_v + CPP_and !std::is_same_v)) ValueId + operator()(L lhs, R rhs) const { using T1 = std::decay_t; using T2 = std::decay_t; @@ -58,7 +64,7 @@ struct SubtractImpl { } } else if constexpr (std::is_same_v) { if constexpr (std::is_same_v) { - return Id::makeFromDouble(tstatic_cast(lhs) - rhs); + return Id::makeFromDouble(static_cast(lhs) - rhs); } else if constexpr (std::is_same_v) { return Id::makeFromInt(lhs - rhs); } From 598c0fab93a3d2734d6ab7b85f5119f924e2a8a1 Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Fri, 23 Jan 2026 14:31:54 +0100 Subject: [PATCH 10/23] removed debug logs --- src/engine/sparqlExpressions/NumericBinaryExpressions.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp index 7e6fc98c3b..866e3cbc0f 100644 --- a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp +++ b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp @@ -71,12 +71,10 @@ struct SubtractImpl { } else if constexpr (std::is_same_v && std::is_same_v) { // Using - operator implementation in DateYearOrDuration. - AD_LOG_INFO << "Date" << std::endl; return Id::makeFromDate(lhs - rhs); } // For all other operations returning Undefined // It is not allowed to use subtractionn between Date and NumericValue - AD_LOG_INFO << "Undefined" << std::endl; return Id::makeUndefined(); } }; From f40809d840067ef774c39cb4d024c97c19beb684 Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Fri, 23 Jan 2026 14:33:12 +0100 Subject: [PATCH 11/23] fixed bug, where date subtraction gave duration negative arguments --- src/util/DateYearDuration.cpp | 26 +++++++++++---- test/DateYearDurationTest.cpp | 62 ++++++++++++++++------------------- 2 files changed, 47 insertions(+), 41 deletions(-) diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index 46be75a716..9f18d51843 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -360,21 +360,33 @@ void updatePassedTimes(const Date& date1, const Date& date2, int& daysPassed, int minute2 = date2.getMinute(); double second2 = date2.getSecond(); if (hour1 < hour2) { - daysPassed--; // counted one day to much - hoursPassed = - 24 - (hour2 - hour1); // total hours of a day - difference + if (daysPassed > 0) { + daysPassed--; // counted one day to much + hoursPassed = + 24 - (hour2 - hour1); // total hours of a day - difference + } else { + hoursPassed = (hour2 - hour1); + } } else { hoursPassed = (hour1 - hour2); } if (minute1 < minute2) { - hoursPassed--; // same as above just one level down - minutesPassed = 60 - (minute2 - minute1); + if (hoursPassed > 0) { + hoursPassed--; // same as above just one level down + minutesPassed = 60 - (minute2 - minute1); + } else { + minutesPassed = (minute2 - minute1); + } } else { minutesPassed = (minute1 - minute2); } if (second1 < second2) { - minutesPassed--; - secondsPassed = 60 - (second2 - second1); + if (minutesPassed > 0) { + minutesPassed--; + secondsPassed = 60 - (second2 - second1); + } else { + secondsPassed = (second2 - second1); + } } else { secondsPassed = (second1 - second2); } diff --git a/test/DateYearDurationTest.cpp b/test/DateYearDurationTest.cpp index 9bbbfc6c15..793e0088ab 100644 --- a/test/DateYearDurationTest.cpp +++ b/test/DateYearDurationTest.cpp @@ -578,40 +578,6 @@ TEST(DateYearOrDuration, Hashing) { // _____________________________________________________________________________ TEST(DateYearOrDuration, Subtraction) { - // OVERFLOW - /*for (int i = 0; i < 10; ++i) { - auto year = yearGenerator(); - auto month = monthGenerator(); - auto day = dayGenerator(); - auto hour = hourGenerator(); - auto minute = minuteGenerator(); - auto second = secondGenerator(); - auto timeZone = timeZoneGenerator(); - - Date date(year, month, day, hour, minute, second, timeZone); - DateYearOrDuration date1(date); - - auto year2 = yearGenerator(); - auto month2 = monthGenerator(); - auto day2 = dayGenerator(); - auto hour2 = hourGenerator(); - auto minute2 = minuteGenerator(); - auto second2 = secondGenerator(); - auto timeZone2 = timeZoneGenerator(); - - Date date_(year2, month2, day2, hour2, minute2, second2, timeZone2); - DateYearOrDuration date2(date_); - - DateYearOrDuration zero_duration( - DayTimeDuration(DayTimeDuration::Type::Positive, 0)); - ASSERT_EQ(zero_duration, date1 - date1); - ASSERT_EQ(zero_duration, date2 - date2); - - DateYearOrDuration result = date1 - date2; - ASSERT_EQ(true, result.isDayTimeDuration()); - }*/ - // OVERFLOW - // hardcoded test // ____________________________________________________________________________ // Test for Date Subtraction @@ -689,4 +655,32 @@ TEST(DateYearOrDuration, Subtraction) { ASSERT_EQ(DateYearOrDuration( DayTimeDuration(DayTimeDuration::Type::Positive, 1, 10, 9, 1)), result); + // ____________________________________________________________________________ + // Test previous bug where days/hours/minutes passed got negative + // daysPassed < 0 + date1 = DateYearOrDuration(Date(2021, 01, 23, 21, 0, 0)); + date2 = DateYearOrDuration(Date(2021, 01, 23, 23, 0, 0)); + // expected duration of 0d2h0min0sec + result = date1 - date2; + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 0, 2, 0, 0)), + result); + + // hoursPassed < 0 + date1 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 0)); + date2 = DateYearOrDuration(Date(2021, 01, 23, 22, 30, 0)); + // expected duration of 0d0h20min0sec + result = date1 - date2; + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 0, 0, 20, 0)), + result); + + // minutesPassed < 0 + date1 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 03)); + date2 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 43)); + // expected duration of 0d0h0min40sec + result = date1 - date2; + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 0, 0, 0, 40)), + result); } From 4b5d95c80a3e32a17e67757adeba99313e904ceb Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Fri, 23 Jan 2026 14:53:21 +0100 Subject: [PATCH 12/23] fixed sonar issues --- .../sparqlExpressions/NumericBinaryExpressions.cpp | 2 -- src/util/DateYearDuration.cpp | 11 ++++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp index 866e3cbc0f..33c527188f 100644 --- a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp +++ b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp @@ -40,8 +40,6 @@ NARY_EXPRESSION(DivideExpressionByZeroIsNan, 2, using Add = MakeNumericExpression>; NARY_EXPRESSION(AddExpression, 2, FV); -// using Subtract = MakeNumericExpression>; -// NARY_EXPRESSION(SubtractExpression, 2, FV); // _____________________________________________________________________________ // Subtract. struct SubtractImpl { diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index 9f18d51843..2794c7a61b 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -344,7 +344,7 @@ std::optional DateYearOrDuration::convertToXsdDate( // _____________________________________________________________________________ #ifndef REDUCED_FEATURE_SET_FOR_CPP17 -void updatePassedTimes(const Date& date1, const Date& date2, int& daysPassed, +void updatePassedTimes(const Date& date1, const Date& date2, long& daysPassed, int& hoursPassed, int& minutesPassed, double& secondsPassed) { // helper function for Subtraction @@ -406,9 +406,10 @@ void updatePassedTimes(const Date& date1, const Date& date2, int& daysPassed, secondsPassed = 60.0 - second2; minutesPassed = 60 - - (minute2 + 1 * (secondsPassed > - 0.0)); // we add 1 because the seconds added a minute - hoursPassed = 24 - (hour2 + 1 * (minutesPassed > 0)); + (minute2 + (secondsPassed > 0.0 + ? 1 + : 0)); // we add 1 because the seconds added a minute + hoursPassed = 24 - (hour2 + (minutesPassed > 0 ? 1 : 0)); } } } @@ -428,7 +429,7 @@ DateYearOrDuration DateYearOrDuration::operator-( std::chrono::year_month_day{std::chrono::year(otherDate.getYear()) / otherDate.getMonth() / otherDate.getDay()}; - int daysPassed = + long daysPassed = (std::chrono::sys_days{date1} - std::chrono::sys_days{date2}).count(); int hoursPassed = 0; int minutesPassed = 0; From 6e9b66dd80ea701ad318fc0cdd388938bc1b4e0d Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Tue, 27 Jan 2026 18:50:41 +0100 Subject: [PATCH 13/23] renaming for NumericOrDateValueGetter --- .../sparqlExpressions/NumericBinaryExpressions.cpp | 9 +++++---- .../SparqlExpressionValueGetters.cpp | 2 +- .../SparqlExpressionValueGetters.h | 14 +++++++------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp index 33c527188f..daec1814be 100644 --- a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp +++ b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp @@ -43,13 +43,13 @@ NARY_EXPRESSION(AddExpression, 2, FV); // _____________________________________________________________________________ // Subtract. struct SubtractImpl { - ValueId operator()(NumericOrDate lhs, NumericOrDate rhs) const { + ValueId operator()(NumericOrDateValue lhs, NumericOrDateValue rhs) const { return std::visit(SubtractImpl{}, lhs, rhs); } CPP_template(typename L, typename R)( - requires(!std::is_same_v - CPP_and !std::is_same_v)) ValueId + requires(!std::is_same_v + CPP_and !std::is_same_v)) ValueId operator()(L lhs, R rhs) const { using T1 = std::decay_t; using T2 = std::decay_t; @@ -76,7 +76,8 @@ struct SubtractImpl { return Id::makeUndefined(); } }; -NARY_EXPRESSION(SubtractExpression, 2, FV); +NARY_EXPRESSION(SubtractExpression, 2, + FV); // _____________________________________________________________________________ // Power. diff --git a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp index 5c2920cd7b..8a77561f3f 100644 --- a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp +++ b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.cpp @@ -47,7 +47,7 @@ NumericValue NumericValueGetter::operator()( } // _____________________________________________________________________________ -NumericOrDate NumericOrDateGetter::operator()( +NumericOrDateValue NumericOrDateValueGetter::operator()( ValueId id, const sparqlExpression::EvaluationContext*) const { switch (id.getDatatype()) { case Datatype::Double: diff --git a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h index f7deb74ad4..b1f013f40b 100644 --- a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h +++ b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h @@ -40,7 +40,7 @@ using IntOrDouble = std::variant; // The input to an expression that expects a numeric value or a date. // Will be used in `NumericBinaryExpressions.cpp` to allow for subtraction of // Dates. -using NumericOrDate = +using NumericOrDateValue = std::variant; // Return type for `DatatypeValueGetter`. @@ -107,17 +107,17 @@ struct NumericValueGetter : Mixin { NumericValue operator()(ValueId id, const EvaluationContext*) const; }; -// Return `NumericOrDate` which is then used as the input to numeric +// Return `NumericOrDateValue` which is then used as the input to numeric // expressions. -struct NumericOrDateGetter : Mixin { - using Mixin::operator(); +struct NumericOrDateValueGetter : Mixin { + using Mixin::operator(); // same as in NumericValueGetter - NumericOrDate operator()(const LiteralOrIri&, - const EvaluationContext*) const { + NumericOrDateValue operator()(const LiteralOrIri&, + const EvaluationContext*) const { return NotNumeric{}; } - NumericOrDate operator()(ValueId id, const EvaluationContext*) const; + NumericOrDateValue operator()(ValueId id, const EvaluationContext*) const; }; /// Return the type exactly as it was passed in. From c9346890c10c3af7466f3dfcaeb153956ceb4959 Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Wed, 28 Jan 2026 17:53:04 +0100 Subject: [PATCH 14/23] fixed bug in Date Subtraction --- src/util/DateYearDuration.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index 2794c7a61b..6eb19cf790 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -359,7 +359,7 @@ void updatePassedTimes(const Date& date1, const Date& date2, long& daysPassed, int hour2 = date2.getHour(); int minute2 = date2.getMinute(); double second2 = date2.getSecond(); - if (hour1 < hour2) { + if (hour1 <= hour2) { if (daysPassed > 0) { daysPassed--; // counted one day to much hoursPassed = @@ -370,7 +370,7 @@ void updatePassedTimes(const Date& date1, const Date& date2, long& daysPassed, } else { hoursPassed = (hour1 - hour2); } - if (minute1 < minute2) { + if (minute1 <= minute2) { if (hoursPassed > 0) { hoursPassed--; // same as above just one level down minutesPassed = 60 - (minute2 - minute1); @@ -380,7 +380,7 @@ void updatePassedTimes(const Date& date1, const Date& date2, long& daysPassed, } else { minutesPassed = (minute1 - minute2); } - if (second1 < second2) { + if (second1 <= second2) { if (minutesPassed > 0) { minutesPassed--; secondsPassed = 60 - (second2 - second1); From 6c1b0589bc542d210a0ec34fdaffe2ad35c1edf0 Mon Sep 17 00:00:00 2001 From: Yannik Schnell Date: Wed, 28 Jan 2026 17:54:06 +0100 Subject: [PATCH 15/23] Added Tests for DateSubtraction to ExpressionTests --- test/SparqlExpressionTest.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/SparqlExpressionTest.cpp b/test/SparqlExpressionTest.cpp index c29617b3b8..1ae547db64 100644 --- a/test/SparqlExpressionTest.cpp +++ b/test/SparqlExpressionTest.cpp @@ -49,6 +49,7 @@ auto D = ad_utility::testing::DoubleId; auto B = ad_utility::testing::BoolId; auto I = ad_utility::testing::IntId; auto Voc = ad_utility::testing::VocabId; +auto Dat = ad_utility::testing::DateId; auto U = Id::makeUndefined(); using Ids = std::vector; @@ -403,6 +404,12 @@ TEST(SparqlExpression, arithmeticOperators) { V s{{"true", "", "false", ""}, alloc}; + V dat{{Dat(DateYearOrDuration::parseXsdDatetime, "1909-10-10T10:11:23Z"), + Dat(DateYearOrDuration::parseXsdDatetime, "2009-09-23T01:01:59Z"), + Dat(DateYearOrDuration::parseXsdDatetime, "1959-03-13T13:13:13Z"), + Dat(DateYearOrDuration::parseXsdDatetime, "1889-10-29T00:12:30Z")}, + alloc}; + V allNan{{D(naN), D(naN), D(naN), D(naN)}, alloc}; V i{{I(32), I(-42), I(0), I(5)}, alloc}; @@ -411,6 +418,8 @@ TEST(SparqlExpression, arithmeticOperators) { V bPlusD{{D(2.0), D(-2.0), D(naN), D(1.0)}, alloc}; V bMinusD{{D(0), D(2.0), D(naN), D(1)}, alloc}; V dMinusB{{D(0), D(-2.0), D(naN), D(-1)}, alloc}; + V dMinusDat{{U, U, U, U}, alloc}; + V datMinusD{{U, U, U, U}, alloc}; V bTimesD{{D(1.0), D(-0.0), D(naN), D(0.0)}, alloc}; // Division by zero is `UNDEF`, to change this behavior a runtime parameter // can be set. This is tested explicitly below. @@ -420,6 +429,8 @@ TEST(SparqlExpression, arithmeticOperators) { testPlus(bPlusD, b, d); testMinus(bMinusD, b, d); testMinus(dMinusB, d, b); + testMinus(dMinusDat, d, dat); + testMinus(datMinusD, dat, d); testMultiply(bTimesD, b, d); testDivide(bByD, b, d); testDivide(dByB, d, b); @@ -449,6 +460,21 @@ TEST(SparqlExpression, arithmeticOperators) { testMultiply(times2, mixed, I(2)); testMultiply(times13, mixed, D(1.3)); + // Test for DateTime - DateTime + V minus2000{ + {Dat(DateYearOrDuration::parseXsdDayTimeDuration, "P32954DT13H48M37S"), + Dat(DateYearOrDuration::parseXsdDayTimeDuration, "P3553DT1H1M59S"), + Dat(DateYearOrDuration::parseXsdDayTimeDuration, "P14903DT10H46M47S"), + Dat(DateYearOrDuration::parseXsdDayTimeDuration, "P40239DT23H47M30S")}, + alloc}; + testMinus(minus2000, dat, + Dat(DateYearOrDuration::parseXsdDatetime, "2000-01-01T00:00:00Z")); + + V mixed2{{B(true), I(250), D(-113.2), Voc(4)}, alloc}; + V mixed2MinusDat{{U, U, U, U}, alloc}; + testMinus(mixed2MinusDat, dat, mixed2); + testMinus(mixed2MinusDat, mixed2, dat); + // For division, all results are doubles, so there is no difference between // int and double inputs. testDivide(by2, mixed, I(2)); From eadb522d6b90f8c7e0b6bace1aaf508d3f89af9e Mon Sep 17 00:00:00 2001 From: yarox-1 Date: Wed, 28 Jan 2026 20:01:46 +0100 Subject: [PATCH 16/23] added Tests for NumericOrDateValueGetter | needed to add operator== to NotNumeric --- .../SparqlExpressionValueGetters.h | 4 +++- test/ValueGetterTest.cpp | 24 +++++++++++++++++++ test/ValueGetterTestHelpers.h | 3 +++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h index b1f013f40b..56a744b79b 100644 --- a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h +++ b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h @@ -33,7 +33,9 @@ using Iri = ad_utility::triple_component::Iri; // An empty struct to represent a non-numeric value in a context where only // numeric values make sense. -struct NotNumeric {}; +struct NotNumeric { + bool operator==(const NotNumeric&) const noexcept = default; +}; // The input to an expression that expects a numeric value. using NumericValue = std::variant; using IntOrDouble = std::variant; diff --git a/test/ValueGetterTest.cpp b/test/ValueGetterTest.cpp index 4bbd68fc1e..74bf6961e9 100644 --- a/test/ValueGetterTest.cpp +++ b/test/ValueGetterTest.cpp @@ -287,4 +287,28 @@ TEST(IntValueGetterTest, OperatorWithLit) { t.checkFromLocalAndNormalVocabAndLiteral("", noInt); } +// _____________________________________________________________________________ +TEST(NumericOrDateValueGetterTest, OperatorWithId) { + NumericOrDateValueGetterTester t; + t.checkFromValueId(ValueId::makeFromInt(-42), + Eq(sparqlExpression::detail::NumericOrDateValue(-42))); + // TODO: still problem here: here nearly equal is needed + // t.checkFromValueId(ValueId::makeFromDouble(50.2), + // Eq(sparqlExpression::detail::NumericOrDateValue(50.2))); + t.checkFromValueId(ValueId::makeFromBool(true), + Eq(sparqlExpression::detail::NumericOrDateValue(1))); + t.checkFromValueId( + ValueId::makeFromDate(DateYearOrDuration(Date(2013, 5, 16))), + Eq(sparqlExpression::detail::NumericOrDateValue( + DateYearOrDuration(Date(2013, 5, 16))))); + // TODO: still problem here: Type is making problems + // t.checkFromValueId(ValueId::makeFromDate(DateYearOrDuration(Duration(Type::Positive, + // 102))), Eq(DateYearOrDuration(Duration(Type::Positive, 102)))); + t.checkFromValueId(ValueId::makeUndefined(), + Eq(sparqlExpression::detail::NumericOrDateValue( + sparqlExpression::detail::NotNumeric{}))); + t.checkFromValueId(ValueId::makeFromGeoPoint({3, 4}), + Eq(sparqlExpression::detail::NumericOrDateValue( + sparqlExpression::detail::NotNumeric{}))); +} }; // namespace diff --git a/test/ValueGetterTestHelpers.h b/test/ValueGetterTestHelpers.h index 4aa2fb6512..13ad96a6e4 100644 --- a/test/ValueGetterTestHelpers.h +++ b/test/ValueGetterTestHelpers.h @@ -306,6 +306,9 @@ using GeoPointOrWktTester = GeoPointOrWkt>; using IntValueGetterTester = ValueGetterTester; +using NumericOrDateValueGetterTester = + ValueGetterTester; // _____________________________________________________________________________ inline void checkGeoPointOrWktFromLocalAndNormalVocabAndLiteralForValid( std::string wktInput, Loc sourceLocation = AD_CURRENT_SOURCE_LOC()) { From 7a7cb1579995fc2389c6cef53625eb912cac9a9b Mon Sep 17 00:00:00 2001 From: Yannik Date: Fri, 30 Jan 2026 11:42:28 +0100 Subject: [PATCH 17/23] Update src/engine/sparqlExpressions/SparqlExpressionValueGetters.h Co-authored-by: C. Ullinger --- src/engine/sparqlExpressions/SparqlExpressionValueGetters.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h index 56a744b79b..8c9b32840e 100644 --- a/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h +++ b/src/engine/sparqlExpressions/SparqlExpressionValueGetters.h @@ -113,7 +113,7 @@ struct NumericValueGetter : Mixin { // expressions. struct NumericOrDateValueGetter : Mixin { using Mixin::operator(); - // same as in NumericValueGetter + // same as in `NumericValueGetter` NumericOrDateValue operator()(const LiteralOrIri&, const EvaluationContext*) const { return NotNumeric{}; From 0cd0d3fe26f4291a89dc2f5e02be221efcfc3285 Mon Sep 17 00:00:00 2001 From: Yannik Date: Fri, 30 Jan 2026 11:42:59 +0100 Subject: [PATCH 18/23] Update src/util/DateYearDuration.h Co-authored-by: C. Ullinger --- src/util/DateYearDuration.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/util/DateYearDuration.h b/src/util/DateYearDuration.h index 0794850bbf..65b825eca4 100644 --- a/src/util/DateYearDuration.h +++ b/src/util/DateYearDuration.h @@ -206,8 +206,6 @@ class DateYearOrDuration { static std::optional convertToXsdDate( const DateYearOrDuration& dateValue); - // Changes/Addition - //____________________________________________________________________________ // Subtraction of two DateYearOrDuration Objects. // Result should be used (nodiscard). [[nodiscard]] DateYearOrDuration operator-( From 4c1d239d138cf4e5c57eaeacb552be85e02fdb72 Mon Sep 17 00:00:00 2001 From: Yannik Date: Fri, 30 Jan 2026 11:43:19 +0100 Subject: [PATCH 19/23] Update src/util/DateYearDuration.h Co-authored-by: C. Ullinger --- src/util/DateYearDuration.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/DateYearDuration.h b/src/util/DateYearDuration.h index 65b825eca4..12004b4ce6 100644 --- a/src/util/DateYearDuration.h +++ b/src/util/DateYearDuration.h @@ -207,7 +207,6 @@ class DateYearOrDuration { const DateYearOrDuration& dateValue); // Subtraction of two DateYearOrDuration Objects. - // Result should be used (nodiscard). [[nodiscard]] DateYearOrDuration operator-( const DateYearOrDuration& rhs) const; }; From 792d808e9dcb9b05962613d2a0c53139660d5525 Mon Sep 17 00:00:00 2001 From: yarox-1 Date: Fri, 30 Jan 2026 11:15:37 +0100 Subject: [PATCH 20/23] ValueGetterTested fixed --- test/ValueGetterTest.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/ValueGetterTest.cpp b/test/ValueGetterTest.cpp index 74bf6961e9..08444dfc8b 100644 --- a/test/ValueGetterTest.cpp +++ b/test/ValueGetterTest.cpp @@ -292,18 +292,19 @@ TEST(NumericOrDateValueGetterTest, OperatorWithId) { NumericOrDateValueGetterTester t; t.checkFromValueId(ValueId::makeFromInt(-42), Eq(sparqlExpression::detail::NumericOrDateValue(-42))); - // TODO: still problem here: here nearly equal is needed - // t.checkFromValueId(ValueId::makeFromDouble(50.2), - // Eq(sparqlExpression::detail::NumericOrDateValue(50.2))); + t.checkFromValueId(ValueId::makeFromDouble(50.2), + Optional(VariantWith(DoubleNear(50.2, 0.01)))); t.checkFromValueId(ValueId::makeFromBool(true), Eq(sparqlExpression::detail::NumericOrDateValue(1))); t.checkFromValueId( ValueId::makeFromDate(DateYearOrDuration(Date(2013, 5, 16))), Eq(sparqlExpression::detail::NumericOrDateValue( DateYearOrDuration(Date(2013, 5, 16))))); - // TODO: still problem here: Type is making problems - // t.checkFromValueId(ValueId::makeFromDate(DateYearOrDuration(Duration(Type::Positive, - // 102))), Eq(DateYearOrDuration(Duration(Type::Positive, 102)))); + t.checkFromValueId( + ValueId::makeFromDate(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 102))), + Eq(sparqlExpression::detail::NumericOrDateValue(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 102))))); t.checkFromValueId(ValueId::makeUndefined(), Eq(sparqlExpression::detail::NumericOrDateValue( sparqlExpression::detail::NotNumeric{}))); From 18efa1a61dfbb74bda8d09657fd8c8355f3057ab Mon Sep 17 00:00:00 2001 From: yarox-1 Date: Fri, 30 Jan 2026 11:23:05 +0100 Subject: [PATCH 21/23] grouped DateYearDuration Subtraction Tests --- test/DateYearDurationTest.cpp | 214 +++++++++++++++++----------------- 1 file changed, 109 insertions(+), 105 deletions(-) diff --git a/test/DateYearDurationTest.cpp b/test/DateYearDurationTest.cpp index 793e0088ab..d67d27ae60 100644 --- a/test/DateYearDurationTest.cpp +++ b/test/DateYearDurationTest.cpp @@ -578,109 +578,113 @@ TEST(DateYearOrDuration, Hashing) { // _____________________________________________________________________________ TEST(DateYearOrDuration, Subtraction) { - // hardcoded test - // ____________________________________________________________________________ - // Test for Date Subtraction - DateYearOrDuration test1 = DateYearOrDuration(Date(2012, 12, 24)); - DateYearOrDuration test2 = DateYearOrDuration(Date(2012, 12, 1)); - - DateYearOrDuration result = test1 - test2; - ASSERT_EQ(true, result.isDayTimeDuration()); - ASSERT_EQ( - DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, 23)), - result); - result = test2 - test1; - ASSERT_EQ(true, result.isDayTimeDuration()); - ASSERT_EQ( - DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, 23)), - result); - - test1 = DateYearOrDuration(Date(2012, 12, 24)); - test2 = DateYearOrDuration(Date(2010, 12, 24)); - result = test1 - test2; - ASSERT_EQ(true, result.isDayTimeDuration()); - ASSERT_EQ( - DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, 731)), - test1 - test2); - result = test2 - test1; - ASSERT_EQ(true, result.isDayTimeDuration()); - ASSERT_EQ( - DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, 731)), - result); - - test2 = DateYearOrDuration(Date(1979, 3, 13)); - result = test1 - test2; - ASSERT_EQ(true, result.isDayTimeDuration()); - ASSERT_EQ(DateYearOrDuration( - DayTimeDuration(DayTimeDuration::Type::Positive, 12340)), - result); - - test1 = DateYearOrDuration(Date(1868, 5, 16)); - result = test1 - test2; - ASSERT_EQ(true, result.isDayTimeDuration()); - ASSERT_EQ(DateYearOrDuration( - DayTimeDuration(DayTimeDuration::Type::Positive, 40477)), - result); - // ____________________________________________________________________________ - // Test for DateTime Subtraction - // DateTime - DateTime - DateYearOrDuration date1 = DateYearOrDuration(Date(2012, 12, 22, 12, 6, 12)); - DateYearOrDuration date2 = DateYearOrDuration(Date(2012, 12, 20, 15, 15, 59)); - // expected duration of 1d20h50min13sec - result = date1 - date2; - ASSERT_EQ(DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, - 1, 20, 50, 13)), - result); - result = date2 - date1; - ASSERT_EQ(DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, - 1, 20, 50, 13)), - result); - - date2 = DateYearOrDuration(Date(2010, 1, 13, 10, 32, 15)); - // expected duration of 1074d1h33min57sec - result = date1 - date2; - ASSERT_EQ(DateYearOrDuration(DayTimeDuration(DayTimeDuration::Type::Positive, - 1074, 1, 33, 57)), - result); - - // Date - DateTime - date1 = DateYearOrDuration(Date(2012, 12, 22)); - date2 = DateYearOrDuration(Date(2012, 12, 20, 13, 50, 59)); - // expected duration of 1d10h9min1sec - result = date1 - date2; - ASSERT_EQ(DateYearOrDuration( - DayTimeDuration(DayTimeDuration::Type::Positive, 1, 10, 9, 1)), - result); - result = date2 - date1; - ASSERT_EQ(DateYearOrDuration( - DayTimeDuration(DayTimeDuration::Type::Positive, 1, 10, 9, 1)), - result); - // ____________________________________________________________________________ - // Test previous bug where days/hours/minutes passed got negative - // daysPassed < 0 - date1 = DateYearOrDuration(Date(2021, 01, 23, 21, 0, 0)); - date2 = DateYearOrDuration(Date(2021, 01, 23, 23, 0, 0)); - // expected duration of 0d2h0min0sec - result = date1 - date2; - ASSERT_EQ(DateYearOrDuration( - DayTimeDuration(DayTimeDuration::Type::Positive, 0, 2, 0, 0)), - result); - - // hoursPassed < 0 - date1 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 0)); - date2 = DateYearOrDuration(Date(2021, 01, 23, 22, 30, 0)); - // expected duration of 0d0h20min0sec - result = date1 - date2; - ASSERT_EQ(DateYearOrDuration( - DayTimeDuration(DayTimeDuration::Type::Positive, 0, 0, 20, 0)), - result); - - // minutesPassed < 0 - date1 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 03)); - date2 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 43)); - // expected duration of 0d0h0min40sec - result = date1 - date2; - ASSERT_EQ(DateYearOrDuration( - DayTimeDuration(DayTimeDuration::Type::Positive, 0, 0, 0, 40)), - result); + { + // Test for Date Subtraction + DateYearOrDuration test1 = DateYearOrDuration(Date(2012, 12, 24)); + DateYearOrDuration test2 = DateYearOrDuration(Date(2012, 12, 1)); + + DateYearOrDuration result = test1 - test2; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 23)), + result); + result = test2 - test1; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 23)), + result); + + test1 = DateYearOrDuration(Date(2012, 12, 24)); + test2 = DateYearOrDuration(Date(2010, 12, 24)); + result = test1 - test2; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 731)), + test1 - test2); + result = test2 - test1; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 731)), + result); + + test2 = DateYearOrDuration(Date(1979, 3, 13)); + result = test1 - test2; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 12340)), + result); + + test1 = DateYearOrDuration(Date(1868, 5, 16)); + result = test1 - test2; + ASSERT_EQ(true, result.isDayTimeDuration()); + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 40477)), + result); + } + { + // Test for DateTime Subtraction + // DateTime - DateTime + DateYearOrDuration date1 = + DateYearOrDuration(Date(2012, 12, 22, 12, 6, 12)); + DateYearOrDuration date2 = + DateYearOrDuration(Date(2012, 12, 20, 15, 15, 59)); + // expected duration of 1d20h50min13sec + DateYearOrDuration result = date1 - date2; + ASSERT_EQ(DateYearOrDuration(DayTimeDuration( + DayTimeDuration::Type::Positive, 1, 20, 50, 13)), + result); + result = date2 - date1; + ASSERT_EQ(DateYearOrDuration(DayTimeDuration( + DayTimeDuration::Type::Positive, 1, 20, 50, 13)), + result); + + date2 = DateYearOrDuration(Date(2010, 1, 13, 10, 32, 15)); + // expected duration of 1074d1h33min57sec + result = date1 - date2; + ASSERT_EQ(DateYearOrDuration(DayTimeDuration( + DayTimeDuration::Type::Positive, 1074, 1, 33, 57)), + result); + + // Date - DateTime + date1 = DateYearOrDuration(Date(2012, 12, 22)); + date2 = DateYearOrDuration(Date(2012, 12, 20, 13, 50, 59)); + // expected duration of 1d10h9min1sec + result = date1 - date2; + ASSERT_EQ(DateYearOrDuration(DayTimeDuration( + DayTimeDuration::Type::Positive, 1, 10, 9, 1)), + result); + result = date2 - date1; + ASSERT_EQ(DateYearOrDuration(DayTimeDuration( + DayTimeDuration::Type::Positive, 1, 10, 9, 1)), + result); + } + { + // Test previous bug where days/hours/minutes passed got negative + // daysPassed < 0 + DateYearOrDuration date1 = DateYearOrDuration(Date(2021, 01, 23, 21, 0, 0)); + DateYearOrDuration date2 = DateYearOrDuration(Date(2021, 01, 23, 23, 0, 0)); + // expected duration of 0d2h0min0sec + DateYearOrDuration result = date1 - date2; + ASSERT_EQ(DateYearOrDuration( + DayTimeDuration(DayTimeDuration::Type::Positive, 0, 2, 0, 0)), + result); + + // hoursPassed < 0 + date1 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 0)); + date2 = DateYearOrDuration(Date(2021, 01, 23, 22, 30, 0)); + // expected duration of 0d0h20min0sec + result = date1 - date2; + ASSERT_EQ(DateYearOrDuration(DayTimeDuration( + DayTimeDuration::Type::Positive, 0, 0, 20, 0)), + result); + + // minutesPassed < 0 + date1 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 03)); + date2 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 43)); + // expected duration of 0d0h0min40sec + result = date1 - date2; + ASSERT_EQ(DateYearOrDuration(DayTimeDuration( + DayTimeDuration::Type::Positive, 0, 0, 0, 40)), + result); + } } From 6c1c4bb6df0b5d8dc336a5165576338e39aad868 Mon Sep 17 00:00:00 2001 From: yarox-1 Date: Fri, 30 Jan 2026 12:01:14 +0100 Subject: [PATCH 22/23] Added lambda function to remove redundand Code from SparqlExpressionTest --- test/SparqlExpressionTest.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/test/SparqlExpressionTest.cpp b/test/SparqlExpressionTest.cpp index 1ae547db64..8b1f25651e 100644 --- a/test/SparqlExpressionTest.cpp +++ b/test/SparqlExpressionTest.cpp @@ -397,6 +397,12 @@ TEST(SparqlExpression, arithmeticOperators) { // `DivideExpression`. // // TODO: Also test `UnaryMinusExpression`. + auto createDat = [](std::string timeString, bool fromDateTime = true) { + return Dat((fromDateTime ? DateYearOrDuration::parseXsdDatetime + : DateYearOrDuration::parseXsdDayTimeDuration), + timeString); + }; + V b{{B(true), B(false), B(false), B(true)}, alloc}; V bAsInt{{I(1), I(0), I(0), I(1)}, alloc}; @@ -404,11 +410,10 @@ TEST(SparqlExpression, arithmeticOperators) { V s{{"true", "", "false", ""}, alloc}; - V dat{{Dat(DateYearOrDuration::parseXsdDatetime, "1909-10-10T10:11:23Z"), - Dat(DateYearOrDuration::parseXsdDatetime, "2009-09-23T01:01:59Z"), - Dat(DateYearOrDuration::parseXsdDatetime, "1959-03-13T13:13:13Z"), - Dat(DateYearOrDuration::parseXsdDatetime, "1889-10-29T00:12:30Z")}, - alloc}; + V dat{ + {createDat("1909-10-10T10:11:23Z"), createDat("2009-09-23T01:01:59Z"), + createDat("1959-03-13T13:13:13Z"), createDat("1889-10-29T00:12:30Z")}, + alloc}; V allNan{{D(naN), D(naN), D(naN), D(naN)}, alloc}; @@ -461,14 +466,12 @@ TEST(SparqlExpression, arithmeticOperators) { testMultiply(times13, mixed, D(1.3)); // Test for DateTime - DateTime - V minus2000{ - {Dat(DateYearOrDuration::parseXsdDayTimeDuration, "P32954DT13H48M37S"), - Dat(DateYearOrDuration::parseXsdDayTimeDuration, "P3553DT1H1M59S"), - Dat(DateYearOrDuration::parseXsdDayTimeDuration, "P14903DT10H46M47S"), - Dat(DateYearOrDuration::parseXsdDayTimeDuration, "P40239DT23H47M30S")}, - alloc}; - testMinus(minus2000, dat, - Dat(DateYearOrDuration::parseXsdDatetime, "2000-01-01T00:00:00Z")); + V minus2000{{createDat("P32954DT13H48M37S", false), + createDat("P3553DT1H1M59S", false), + createDat("P14903DT10H46M47S", false), + createDat("P40239DT23H47M30S", false)}, + alloc}; + testMinus(minus2000, dat, createDat("2000-01-01T00:00:00Z")); V mixed2{{B(true), I(250), D(-113.2), Voc(4)}, alloc}; V mixed2MinusDat{{U, U, U, U}, alloc}; From 0f7872087de0b8e0ac6bf96b2e403caa0b997074 Mon Sep 17 00:00:00 2001 From: yarox-1 Date: Tue, 3 Feb 2026 15:42:22 +0100 Subject: [PATCH 23/23] added 'isLongYear()'; Date operator- now returns std::optional; should now be compatible with CPP17 --- .../NumericBinaryExpressions.cpp | 9 +++++- src/util/DateYearDuration.cpp | 15 ++++----- src/util/DateYearDuration.h | 11 ++++++- test/DateYearDurationTest.cpp | 32 ++++++++++--------- 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp index daec1814be..f725f68bee 100644 --- a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp +++ b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp @@ -68,8 +68,15 @@ struct SubtractImpl { } } else if constexpr (std::is_same_v && std::is_same_v) { +#ifndef REDUCED_FEATURE_SET_FOR_CPP17 // Using - operator implementation in DateYearOrDuration. - return Id::makeFromDate(lhs - rhs); + auto difference = lhs - rhs; + if (difference.has_value()) { + return Id::makeFromDate(difference.value()); + } else { + return Id::makeUndefined(); + } +#endif } // For all other operations returning Undefined // It is not allowed to use subtractionn between Date and NumericValue diff --git a/src/util/DateYearDuration.cpp b/src/util/DateYearDuration.cpp index 6eb19cf790..23327978ea 100644 --- a/src/util/DateYearDuration.cpp +++ b/src/util/DateYearDuration.cpp @@ -414,7 +414,7 @@ void updatePassedTimes(const Date& date1, const Date& date2, long& daysPassed, } } -DateYearOrDuration DateYearOrDuration::operator-( +std::optional DateYearOrDuration::operator-( const DateYearOrDuration& rhs) const { if (isDate() && rhs.isDate()) { // Date - Date => Duration | getting time between the two Dates @@ -458,20 +458,19 @@ DateYearOrDuration DateYearOrDuration::operator-( if (isDayTimeDuration() && rhs.isDayTimeDuration()) { // Duration - Duration => Duration | getting new duration that is // rhs.duration-time smaller return; - // TODO: implement + // TODO: can be implemented } if (isDate() && rhs.isDayTimeDuration()) { // Date - Duration => Date | getting new Date from rhs.duration-time earlier - // return; - // TODO: implement + // TODO: can be implemented } - if (isDayTimeDuration() && rhs.isDate()) { - // Duration - Date | not implemented - } + // TODO: subtraction with large year can also be implemented + + // Duration - Date is not implemented // no viable subtraction - throw std::invalid_argument("No Subtraction possible!"); + return std::nullopt; } #endif diff --git a/src/util/DateYearDuration.h b/src/util/DateYearDuration.h index 12004b4ce6..745e7c4423 100644 --- a/src/util/DateYearDuration.h +++ b/src/util/DateYearDuration.h @@ -84,6 +84,12 @@ class DateYearOrDuration { // True iff a complete `Date` is stored and not only a large year. bool isDate() const { return bits_ >> numPayloadDateBits == datetime; } + // True iff a large year is stored. + bool isLongYear() const { + return (bits_ >> numPayloadDateBits == negativeYear) || + (bits_ >> numPayloadDateBits == positiveYear); + } + // True iff constructed with `DayTimeDuration`. bool isDayTimeDuration() const { return bits_ >> numPayloadDurationBits == daytimeDuration; @@ -206,9 +212,12 @@ class DateYearOrDuration { static std::optional convertToXsdDate( const DateYearOrDuration& dateValue); +#ifndef REDUCED_FEATURE_SET_FOR_CPP17 // Subtraction of two DateYearOrDuration Objects. - [[nodiscard]] DateYearOrDuration operator-( + // For undefined subtractions `std::nullopt` is returned. + [[nodiscard]] std::optional operator-( const DateYearOrDuration& rhs) const; +#endif }; #ifdef QLEVER_CPP_17 static_assert(std::is_default_constructible_v); diff --git a/test/DateYearDurationTest.cpp b/test/DateYearDurationTest.cpp index d67d27ae60..6f94940dad 100644 --- a/test/DateYearDurationTest.cpp +++ b/test/DateYearDurationTest.cpp @@ -576,6 +576,7 @@ TEST(DateYearOrDuration, Hashing) { EXPECT_THAT(set, ::testing::UnorderedElementsAre(d1, d2)); } +#ifndef REDUCED_FEATURE_SET_FOR_CPP17 // _____________________________________________________________________________ TEST(DateYearOrDuration, Subtraction) { { @@ -583,12 +584,12 @@ TEST(DateYearOrDuration, Subtraction) { DateYearOrDuration test1 = DateYearOrDuration(Date(2012, 12, 24)); DateYearOrDuration test2 = DateYearOrDuration(Date(2012, 12, 1)); - DateYearOrDuration result = test1 - test2; + DateYearOrDuration result = (test1 - test2).value(); ASSERT_EQ(true, result.isDayTimeDuration()); ASSERT_EQ(DateYearOrDuration( DayTimeDuration(DayTimeDuration::Type::Positive, 23)), result); - result = test2 - test1; + result = (test2 - test1).value(); ASSERT_EQ(true, result.isDayTimeDuration()); ASSERT_EQ(DateYearOrDuration( DayTimeDuration(DayTimeDuration::Type::Positive, 23)), @@ -596,26 +597,26 @@ TEST(DateYearOrDuration, Subtraction) { test1 = DateYearOrDuration(Date(2012, 12, 24)); test2 = DateYearOrDuration(Date(2010, 12, 24)); - result = test1 - test2; + result = (test1 - test2).value(); ASSERT_EQ(true, result.isDayTimeDuration()); ASSERT_EQ(DateYearOrDuration( DayTimeDuration(DayTimeDuration::Type::Positive, 731)), - test1 - test2); - result = test2 - test1; + result); + result = (test2 - test1).value(); ASSERT_EQ(true, result.isDayTimeDuration()); ASSERT_EQ(DateYearOrDuration( DayTimeDuration(DayTimeDuration::Type::Positive, 731)), result); test2 = DateYearOrDuration(Date(1979, 3, 13)); - result = test1 - test2; + result = (test1 - test2).value(); ASSERT_EQ(true, result.isDayTimeDuration()); ASSERT_EQ(DateYearOrDuration( DayTimeDuration(DayTimeDuration::Type::Positive, 12340)), result); test1 = DateYearOrDuration(Date(1868, 5, 16)); - result = test1 - test2; + result = (test1 - test2).value(); ASSERT_EQ(true, result.isDayTimeDuration()); ASSERT_EQ(DateYearOrDuration( DayTimeDuration(DayTimeDuration::Type::Positive, 40477)), @@ -629,18 +630,18 @@ TEST(DateYearOrDuration, Subtraction) { DateYearOrDuration date2 = DateYearOrDuration(Date(2012, 12, 20, 15, 15, 59)); // expected duration of 1d20h50min13sec - DateYearOrDuration result = date1 - date2; + DateYearOrDuration result = (date1 - date2).value(); ASSERT_EQ(DateYearOrDuration(DayTimeDuration( DayTimeDuration::Type::Positive, 1, 20, 50, 13)), result); - result = date2 - date1; + result = (date2 - date1).value(); ASSERT_EQ(DateYearOrDuration(DayTimeDuration( DayTimeDuration::Type::Positive, 1, 20, 50, 13)), result); date2 = DateYearOrDuration(Date(2010, 1, 13, 10, 32, 15)); // expected duration of 1074d1h33min57sec - result = date1 - date2; + result = (date1 - date2).value(); ASSERT_EQ(DateYearOrDuration(DayTimeDuration( DayTimeDuration::Type::Positive, 1074, 1, 33, 57)), result); @@ -649,11 +650,11 @@ TEST(DateYearOrDuration, Subtraction) { date1 = DateYearOrDuration(Date(2012, 12, 22)); date2 = DateYearOrDuration(Date(2012, 12, 20, 13, 50, 59)); // expected duration of 1d10h9min1sec - result = date1 - date2; + result = (date1 - date2).value(); ASSERT_EQ(DateYearOrDuration(DayTimeDuration( DayTimeDuration::Type::Positive, 1, 10, 9, 1)), result); - result = date2 - date1; + result = (date2 - date1).value(); ASSERT_EQ(DateYearOrDuration(DayTimeDuration( DayTimeDuration::Type::Positive, 1, 10, 9, 1)), result); @@ -664,7 +665,7 @@ TEST(DateYearOrDuration, Subtraction) { DateYearOrDuration date1 = DateYearOrDuration(Date(2021, 01, 23, 21, 0, 0)); DateYearOrDuration date2 = DateYearOrDuration(Date(2021, 01, 23, 23, 0, 0)); // expected duration of 0d2h0min0sec - DateYearOrDuration result = date1 - date2; + DateYearOrDuration result = (date1 - date2).value(); ASSERT_EQ(DateYearOrDuration( DayTimeDuration(DayTimeDuration::Type::Positive, 0, 2, 0, 0)), result); @@ -673,7 +674,7 @@ TEST(DateYearOrDuration, Subtraction) { date1 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 0)); date2 = DateYearOrDuration(Date(2021, 01, 23, 22, 30, 0)); // expected duration of 0d0h20min0sec - result = date1 - date2; + result = (date1 - date2).value(); ASSERT_EQ(DateYearOrDuration(DayTimeDuration( DayTimeDuration::Type::Positive, 0, 0, 20, 0)), result); @@ -682,9 +683,10 @@ TEST(DateYearOrDuration, Subtraction) { date1 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 03)); date2 = DateYearOrDuration(Date(2021, 01, 23, 22, 10, 43)); // expected duration of 0d0h0min40sec - result = date1 - date2; + result = (date1 - date2).value(); ASSERT_EQ(DateYearOrDuration(DayTimeDuration( DayTimeDuration::Type::Positive, 0, 0, 0, 40)), result); } } +#endif