import codecs
from datetime import date
-from ..adapt import Dumper
+from ..adapt import Dumper, Loader
+from ..proto import AdaptContext
from .oids import builtins
@property
def oid(self) -> int:
return self.DATE_OID
+
+
+@Loader.text(builtins["date"].oid)
+class DateLoader(Loader):
+
+ _decode = codecs.lookup("ascii").decode
+
+ def __init__(self, oid: int, context: AdaptContext):
+ super().__init__(oid, context)
+
+ if self.connection:
+ ds = self.connection.pgconn.parameter_status(b"DateStyle")
+ if not ds or ds.startswith(b"ISO"):
+ pass
+ elif ds.startswith(b"German"):
+ self.load = self.load_dmy # type: ignore
+ elif ds.startswith(b"SQL"):
+ self.load = self.load_mdy # type: ignore
+ elif ds.startswith(b"Postgres"):
+ self.load = self.load_mdy # type: ignore
+
+ def load(self, data: bytes) -> date:
+ return date(int(data[:4]), int(data[5:7]), int(data[8:]))
+
+ def load_dmy(self, data: bytes) -> date:
+ return date(int(data[6:]), int(data[3:5]), int(data[:2]))
+
+ def load_mdy(self, data: bytes) -> date:
+ return date(int(data[6:]), int(data[:2]), int(data[3:5]))
import datetime as dt
import pytest
+from psycopg3.adapt import Format
+
@pytest.mark.parametrize(
"val, expr",
cur.execute(f"set datestyle = ISO, {datestyle_in}")
cur.execute("select '2000-01-02'::date = %s", (dt.date(2000, 1, 2),))
assert cur.fetchone()[0]
+
+
+@pytest.mark.parametrize(
+ "val, expr",
+ [
+ (dt.date(1, 1, 1), "'0001-01-01'::date"),
+ (dt.date(1000, 1, 1), "'1000-01-01'::date"),
+ (dt.date(2000, 1, 1), "'2000-01-01'::date"),
+ (dt.date(2000, 12, 31), "'2000-12-31'::date"),
+ (dt.date(3000, 1, 1), "'3000-01-01'::date"),
+ ],
+)
+def test_load_date(conn, val, expr):
+ cur = conn.cursor()
+ cur.execute("select %s" % expr)
+ assert cur.fetchone()[0] == val
+
+
+@pytest.mark.xfail # TODO: binary load
+@pytest.mark.parametrize(
+ "val, expr", [(dt.date(2000, 1, 1), "'2000-01-01'::date")],
+)
+def test_load_date_binary(conn, val, expr):
+ cur = conn.cursor(format=Format.BINARY)
+ cur.execute("select %s" % expr)
+ assert cur.fetchone()[0] == val
+
+
+@pytest.mark.parametrize("datestyle_out", ["ISO", "Postgres", "SQL", "German"])
+def test_load_date_datestyle(conn, datestyle_out):
+ cur = conn.cursor()
+ cur.execute(f"set datestyle = {datestyle_out}, YMD")
+ cur.execute("select '2000-01-02'::date")
+ assert cur.fetchone()[0] == dt.date(2000, 1, 2)