diff --git a/src/iceberg/expression/literal.cc b/src/iceberg/expression/literal.cc index aea719c84..a1222ff69 100644 --- a/src/iceberg/expression/literal.cc +++ b/src/iceberg/expression/literal.cc @@ -27,6 +27,7 @@ #include "iceberg/util/checked_cast.h" #include "iceberg/util/conversions.h" #include "iceberg/util/macros.h" +#include "iceberg/util/temporal_util.h" namespace iceberg { @@ -209,8 +210,10 @@ Result LiteralCaster::CastFromTimestamp( auto timestamp_val = std::get(literal.value_); switch (target_type->type_id()) { - case TypeId::kDate: - return NotImplemented("Cast from Timestamp to Date is not implemented yet"); + case TypeId::kDate: { + ICEBERG_ASSIGN_OR_RAISE(auto days, TemporalUtils::ExtractDay(literal)); + return Literal::Date(std::get(days.value())); + } case TypeId::kTimestampTz: return Literal::TimestampTz(timestamp_val); default: @@ -224,8 +227,10 @@ Result LiteralCaster::CastFromTimestampTz( auto micros = std::get(literal.value_); switch (target_type->type_id()) { - case TypeId::kDate: - return NotImplemented("Cast from TimestampTz to Date is not implemented yet"); + case TypeId::kDate: { + ICEBERG_ASSIGN_OR_RAISE(auto days, TemporalUtils::ExtractDay(literal)); + return Literal::Date(std::get(days.value())); + } case TypeId::kTimestamp: return Literal::Timestamp(micros); default: diff --git a/src/iceberg/test/literal_test.cc b/src/iceberg/test/literal_test.cc index 0dd291d5c..ca2a40621 100644 --- a/src/iceberg/test/literal_test.cc +++ b/src/iceberg/test/literal_test.cc @@ -27,6 +27,7 @@ #include "iceberg/type.h" #include "matchers.h" +#include "temporal_test_helper.h" namespace iceberg { @@ -689,6 +690,51 @@ INSTANTIATE_TEST_SUITE_P( .source_literal = Literal::Long(42L), .target_type = timestamp_tz(), .expected_literal = Literal::TimestampTz(42L)}, + CastLiteralTestParam{ + .test_name = "TimestampToDate", + .source_literal = + Literal::Timestamp(TemporalTestHelper::CreateTimestamp({.year = 2021, + .month = 6, + .day = 1, + .hour = 11, + .minute = 43, + .second = 20})), + .target_type = date(), + .expected_literal = Literal::Date( + TemporalTestHelper::CreateDate({.year = 2021, .month = 6, .day = 1}))}, + CastLiteralTestParam{ + .test_name = "TimestampTzToDate", + .source_literal = Literal::TimestampTz( + TemporalTestHelper::CreateTimestampTz({.year = 2021, + .month = 1, + .day = 1, + .hour = 7, + .minute = 43, + .second = 20, + .tz_offset_minutes = 480})), + .target_type = date(), + .expected_literal = Literal::Date( + TemporalTestHelper::CreateDate({.year = 2020, .month = 12, .day = 31}))}, + CastLiteralTestParam{.test_name = "EpochToDate", + .source_literal = Literal::Timestamp( + TemporalTestHelper::CreateTimestamp({.year = 1970, + .month = 1, + .day = 1, + .hour = 0, + .minute = 0, + .second = 0})), + .target_type = date(), + .expected_literal = Literal::Date(0)}, + CastLiteralTestParam{.test_name = "TimestampBeforeEpochToDate", + .source_literal = Literal::Timestamp( + TemporalTestHelper::CreateTimestamp({.year = 1969, + .month = 12, + .day = 31, + .hour = 23, + .minute = 59, + .second = 59})), + .target_type = date(), + .expected_literal = Literal::Date(-1)}, // Float cast tests CastLiteralTestParam{.test_name = "FloatToDouble", .source_literal = Literal::Float(2.0f),