This is an automated email from the ASF dual-hosted git repository.
blue pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/master by this push:
new 167a8ccd7c Python: Support creating a DateLiteral from a date (#6123)
167a8ccd7c is described below
commit 167a8ccd7c578296c40f8fc61c90135e71cf1183
Author: Douglas Drinka <[email protected]>
AuthorDate: Sun Nov 6 17:28:51 2022 -0700
Python: Support creating a DateLiteral from a date (#6123)
Closes #6120.
---
python/pyiceberg/expressions/literals.py | 9 ++++++++-
python/pyiceberg/utils/datetime.py | 7 ++++++-
python/tests/expressions/test_literals.py | 12 ++++++++++++
python/tests/test_transforms.py | 11 +++++++----
4 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/python/pyiceberg/expressions/literals.py
b/python/pyiceberg/expressions/literals.py
index 458cbda41d..ac4c0711a9 100644
--- a/python/pyiceberg/expressions/literals.py
+++ b/python/pyiceberg/expressions/literals.py
@@ -23,6 +23,7 @@ from __future__ import annotations
import struct
from abc import ABC, abstractmethod
+from datetime import date
from decimal import ROUND_HALF_UP, Decimal
from functools import singledispatch, singledispatchmethod
from typing import (
@@ -50,6 +51,7 @@ from pyiceberg.types import (
UUIDType,
)
from pyiceberg.utils.datetime import (
+ date_str_to_days,
date_to_days,
micros_to_days,
time_to_micros,
@@ -164,6 +166,11 @@ def _(value: Decimal) -> Literal[Decimal]:
return DecimalLiteral(value)
[email protected](date)
+def _(value: date) -> Literal[int]:
+ return DateLiteral(date_to_days(value))
+
+
class AboveMax(Singleton):
@property
def value(self):
@@ -395,7 +402,7 @@ class StringLiteral(Literal[str]):
@to.register(DateType)
def _(self, type_var: DateType) -> Optional[Literal[int]]:
try:
- return DateLiteral(date_to_days(self.value))
+ return DateLiteral(date_str_to_days(self.value))
except (TypeError, ValueError):
return None
diff --git a/python/pyiceberg/utils/datetime.py
b/python/pyiceberg/utils/datetime.py
index 76a5e9d484..31a8e6193d 100644
--- a/python/pyiceberg/utils/datetime.py
+++ b/python/pyiceberg/utils/datetime.py
@@ -47,11 +47,16 @@ def micros_to_time(micros: int) -> time:
return time(hour=hours, minute=minutes, second=seconds,
microsecond=microseconds)
-def date_to_days(date_str: str) -> int:
+def date_str_to_days(date_str: str) -> int:
"""Converts an ISO-8601 formatted date to days from 1970-01-01"""
return (date.fromisoformat(date_str) - EPOCH_DATE).days
+def date_to_days(date_val: date) -> int:
+ """Converts a Python date object to days from 1970-01-01"""
+ return (date_val - EPOCH_DATE).days
+
+
def days_to_date(days: int) -> date:
"""Creates a date from the number of days from 1970-01-01"""
return EPOCH_DATE + timedelta(days)
diff --git a/python/tests/expressions/test_literals.py
b/python/tests/expressions/test_literals.py
index 019c925bfc..f34c8ae683 100644
--- a/python/tests/expressions/test_literals.py
+++ b/python/tests/expressions/test_literals.py
@@ -339,6 +339,17 @@ def test_string_to_decimal_literal():
# MISC
+def test_python_date_conversion():
+ one_day_str = "2022-03-28"
+ one_day_date = datetime.date(2022, 3, 28)
+
+ from_str_lit = literal(one_day_str).to(DateType())
+ from_date_lit = literal(one_day_date)
+
+ assert isinstance(from_date_lit, DateLiteral)
+ assert from_str_lit == from_date_lit
+
+
@pytest.mark.parametrize(
"lit, primitive_type",
[
@@ -348,6 +359,7 @@ def test_string_to_decimal_literal():
(literal(34.11), FloatType()),
(literal(3.5028235e38), DoubleType()),
(literal(Decimal(34.55).quantize(Decimal("0.01"))), DecimalType(9, 2)),
+ (literal(datetime.date(2017, 8, 18)), DateType()),
(literal("2017-08-18"), DateType()),
(literal("14:21:01.919"), TimeType()),
(literal("2017-08-18T14:21:01.919"), TimestampType()),
diff --git a/python/tests/test_transforms.py b/python/tests/test_transforms.py
index eec3e4aebe..3e4e63494a 100644
--- a/python/tests/test_transforms.py
+++ b/python/tests/test_transforms.py
@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
# pylint: disable=eval-used,protected-access
+from datetime import date
from decimal import Decimal
from uuid import UUID
@@ -51,6 +52,7 @@ from pyiceberg.types import (
UUIDType,
)
from pyiceberg.utils.datetime import (
+ date_str_to_days,
date_to_days,
time_to_micros,
timestamp_to_micros,
@@ -65,7 +67,8 @@ from pyiceberg.utils.iceberg_base_model import
IcebergBaseModel
(1, IntegerType(), 1392991556),
(34, IntegerType(), 2017239379),
(34, LongType(), 2017239379),
- (date_to_days("2017-11-16"), DateType(), -653330422),
+ (date_to_days(date(2017, 11, 16)), DateType(), -653330422),
+ (date_str_to_days("2017-11-16"), DateType(), -653330422),
(time_to_micros("22:31:08"), TimeType(), -662762989),
(
timestamp_to_micros("2017-11-16T22:31:08"),
@@ -144,15 +147,15 @@ def test_string_with_surrogate_pair():
@pytest.mark.parametrize(
- "date,date_transform,expected",
+ "date_val,date_transform,expected",
[
(47, YearTransform(), "2017"),
(575, MonthTransform(), "2017-12"),
(17501, DayTransform(), "2017-12-01"),
],
)
-def test_date_to_human_string(date, date_transform, expected):
- assert date_transform.to_human_string(DateType(), date) == expected
+def test_date_to_human_string(date_val, date_transform, expected):
+ assert date_transform.to_human_string(DateType(), date_val) == expected
@pytest.mark.parametrize(