This is an automated email from the ASF dual-hosted git repository.
gangwu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-cpp.git
The following commit(s) were added to refs/heads/main by this push:
new 40834ddd fix: YearTransform return years since 1970 (#495)
40834ddd is described below
commit 40834ddd7c33d8b9a67da3b62d1d132a9c42c129
Author: wzhuo <[email protected]>
AuthorDate: Thu Jan 8 21:52:44 2026 +0800
fix: YearTransform return years since 1970 (#495)
---
src/iceberg/test/eval_expr_test.cc | 2 +-
src/iceberg/test/transform_test.cc | 18 +++++++++++-------
src/iceberg/transform.h | 8 ++++----
src/iceberg/transform_function.h | 12 ++++++++----
src/iceberg/util/temporal_util.cc | 4 ++--
5 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/src/iceberg/test/eval_expr_test.cc
b/src/iceberg/test/eval_expr_test.cc
index 880f1ffb..39cb2a97 100644
--- a/src/iceberg/test/eval_expr_test.cc
+++ b/src/iceberg/test/eval_expr_test.cc
@@ -161,7 +161,7 @@ TEST_F(BoundExpressionTest, YearTransform) {
// Evaluate (2021)
ICEBERG_UNWRAP_OR_FAIL(auto result, bound_transform->Evaluate(*struct_like));
EXPECT_FALSE(result.IsNull());
- EXPECT_EQ(std::get<int32_t>(result.value()), 2021); // Year value
+ EXPECT_EQ(std::get<int32_t>(result.value()), 2021 - 1970); // Year value
}
TEST_F(BoundExpressionTest, MonthTransform) {
diff --git a/src/iceberg/test/transform_test.cc
b/src/iceberg/test/transform_test.cc
index 7f0514df..47a1e87e 100644
--- a/src/iceberg/test/transform_test.cc
+++ b/src/iceberg/test/transform_test.cc
@@ -459,7 +459,7 @@ INSTANTIATE_TEST_SUITE_P(
.hour = 11,
.minute = 43,
.second =
20})),
- .expected = Literal::Int(2021)},
+ .expected = Literal::Int(2021 - 1970)},
TransformParam{
.str = "TimestampTz",
// 2021-01-01T07:43:20+08:00, which is 2020-12-31T23:43:20Z
@@ -472,12 +472,12 @@ INSTANTIATE_TEST_SUITE_P(
.minute = 43,
.second = 20,
.tz_offset_minutes =
480})),
- .expected = Literal::Int(2020)},
+ .expected = Literal::Int(2020 - 1970)},
TransformParam{.str = "Date",
.source_type = iceberg::date(),
.source = Literal::Date(TemporalTestHelper::CreateDate(
{.year = 2052, .month = 2, .day = 20})),
- .expected = Literal::Int(2052)}),
+ .expected = Literal::Int(2052 - 1970)}),
[](const ::testing::TestParamInfo<TransformParam>& info) { return
info.param.str; });
class MonthTransformTest : public ::testing::TestWithParam<TransformParam> {};
@@ -2061,7 +2061,8 @@ TEST_F(TransformProjectStrictTest, YearStrictLessThan) {
std::move(projected));
EXPECT_EQ(unbound_projected->op(), Expression::Operation::kLt);
EXPECT_EQ(unbound_projected->literals().size(), 1);
- EXPECT_EQ(std::get<int32_t>(unbound_projected->literals().front().value()),
2021);
+ EXPECT_EQ(std::get<int32_t>(unbound_projected->literals().front().value()),
+ 2021 - 1970);
}
TEST_F(TransformProjectStrictTest, YearStrictGreaterThanOrEqual) {
@@ -2085,7 +2086,8 @@ TEST_F(TransformProjectStrictTest,
YearStrictGreaterThanOrEqual) {
std::move(projected));
EXPECT_EQ(unbound_projected->op(), Expression::Operation::kGt);
EXPECT_EQ(unbound_projected->literals().size(), 1);
- EXPECT_EQ(std::get<int32_t>(unbound_projected->literals().front().value()),
2020);
+ EXPECT_EQ(std::get<int32_t>(unbound_projected->literals().front().value()),
+ 2020 - 1970);
}
TEST_F(TransformProjectStrictTest, YearStrictNotEqual) {
@@ -2109,7 +2111,8 @@ TEST_F(TransformProjectStrictTest, YearStrictNotEqual) {
std::move(projected));
EXPECT_EQ(unbound_projected->op(), Expression::Operation::kNotEq);
EXPECT_EQ(unbound_projected->literals().size(), 1);
- EXPECT_EQ(std::get<int32_t>(unbound_projected->literals().front().value()),
2021);
+ EXPECT_EQ(std::get<int32_t>(unbound_projected->literals().front().value()),
+ 2021 - 1970);
}
TEST_F(TransformProjectStrictTest, MonthStrictLessThan) {
@@ -2218,7 +2221,8 @@ TEST_F(TransformProjectStrictTest, YearStrictUpperBound) {
std::move(projected));
EXPECT_EQ(unbound_projected->op(), Expression::Operation::kLt);
EXPECT_EQ(unbound_projected->literals().size(), 1);
- EXPECT_EQ(std::get<int32_t>(unbound_projected->literals().front().value()),
2018);
+ EXPECT_EQ(std::get<int32_t>(unbound_projected->literals().front().value()),
+ 2018 - 1970);
}
TEST_F(TransformProjectStrictTest, VoidStrictReturnsNull) {
diff --git a/src/iceberg/transform.h b/src/iceberg/transform.h
index 1044e264..36da46d9 100644
--- a/src/iceberg/transform.h
+++ b/src/iceberg/transform.h
@@ -111,25 +111,25 @@ class ICEBERG_EXPORT Transform : public util::Formattable
{
/// \brief Creates a shared singleton instance of the Year transform.
///
- /// Extracts the year portion from a date or timestamp.
+ /// Extracts the number of years from a date or timestamp since the epoch.
/// \return A shared pointer to the Year transform.
static std::shared_ptr<Transform> Year();
/// \brief Creates a shared singleton instance of the Month transform.
///
- /// Extracts the month portion from a date or timestamp.
+ /// Extracts the number of months from a date or timestamp since the epoch.
/// \return A shared pointer to the Month transform.
static std::shared_ptr<Transform> Month();
/// \brief Creates a shared singleton instance of the Day transform.
///
- /// Extracts the day portion from a date or timestamp.
+ /// Extracts the number of days from a date or timestamp since the epoch.
/// \return A shared pointer to the Day transform.
static std::shared_ptr<Transform> Day();
/// \brief Creates a shared singleton instance of the Hour transform.
///
- /// Extracts the hour portion from a timestamp.
+ /// Extracts the number of hours from a timestamp since the epoch.
/// \return A shared pointer to the Hour transform.
static std::shared_ptr<Transform> Hour();
diff --git a/src/iceberg/transform_function.h b/src/iceberg/transform_function.h
index c8670824..a44e6c7a 100644
--- a/src/iceberg/transform_function.h
+++ b/src/iceberg/transform_function.h
@@ -100,7 +100,8 @@ class ICEBERG_EXPORT TruncateTransform : public
TransformFunction {
int32_t width_;
};
-/// \brief Year transform that extracts the year component from timestamp
inputs.
+/// \brief Year transform that extracts the number of years from timestamp
inputs since
+/// the epoch.
class ICEBERG_EXPORT YearTransform : public TransformFunction {
public:
/// \param source_type Must be a timestamp type.
@@ -119,7 +120,8 @@ class ICEBERG_EXPORT YearTransform : public
TransformFunction {
std::shared_ptr<Type> const& source_type);
};
-/// \brief Month transform that extracts the month component from timestamp
inputs.
+/// \brief Month transform that extracts the number of months from timestamp
inputs since
+/// the epoch.
class ICEBERG_EXPORT MonthTransform : public TransformFunction {
public:
/// \param source_type Must be a timestamp type.
@@ -138,7 +140,8 @@ class ICEBERG_EXPORT MonthTransform : public
TransformFunction {
std::shared_ptr<Type> const& source_type);
};
-/// \brief Day transform that extracts the day of the month from timestamp
inputs.
+/// \brief Day transform that extracts the number of days from timestamp
inputs since the
+/// epoch.
class ICEBERG_EXPORT DayTransform : public TransformFunction {
public:
/// \param source_type Must be a timestamp type.
@@ -161,7 +164,8 @@ class ICEBERG_EXPORT DayTransform : public
TransformFunction {
std::shared_ptr<Type> const& source_type);
};
-/// \brief Hour transform that extracts the hour component from timestamp
inputs.
+/// \brief Hour transform that extracts the number of hours from timestamp
inputs since
+/// the epoch.
class ICEBERG_EXPORT HourTransform : public TransformFunction {
public:
/// \param source_type Must be a timestamp type.
diff --git a/src/iceberg/util/temporal_util.cc
b/src/iceberg/util/temporal_util.cc
index 0112e492..05aafb96 100644
--- a/src/iceberg/util/temporal_util.cc
+++ b/src/iceberg/util/temporal_util.cc
@@ -68,14 +68,14 @@ template <>
Result<Literal> ExtractYearImpl<TypeId::kDate>(const Literal& literal) {
auto value = std::get<int32_t>(literal.value());
auto ymd = DateToYmd(value);
- return Literal::Int(static_cast<int32_t>(ymd.year()));
+ return Literal::Int((ymd.year() - kEpochYmd.year()).count());
}
template <>
Result<Literal> ExtractYearImpl<TypeId::kTimestamp>(const Literal& literal) {
auto value = std::get<int64_t>(literal.value());
auto ymd = TimestampToYmd(value);
- return Literal::Int(static_cast<int32_t>(ymd.year()));
+ return Literal::Int((ymd.year() - kEpochYmd.year()).count());
}
template <>