Skip to content

Make PandasCursor's temporal dtypes and fetched types depend only on the Athena type #1219

Closed

Description

@laughingman7743

Part of #1212.

Summary

Make PandasCursor's temporal dtypes and fetched types depend only on the Athena type, as in the contract table of #1212. This is a breaking change; it ships in 4.2.0 with migration notes.

Facts

PandasCursor fixes the dtypes of numeric and string columns with dtype, but not those of date, time, and timestamp. It passes them as parse_dates, so pandas infers the unit from the values, again for each chunk, and keeps a column as text when a value does not parse.

Changes

  • timestamp is always datetime64[us]. Today it is [s] without fractions (the pyarrow engine) or when all NULL, [ns] for 7 or more fractional digits, str when such a column also holds values outside the nanosecond range, and different per chunk.
    • pandas 3.0.6 cannot take datetime64[us] as a read_csv dtype. Reading the text, truncating fractions to six digits, and then calling to_datetime(format="ISO8601").dt.as_unit("us") gave datetime64[us] for every case above.
  • timestamp with time zone is datetime64[us, UTC]. Today the dtype carries the zone of the data, such as datetime64[us, Asia/Tokyo], and a column with two zones is object.
  • date is datetime64[us] from both CSV and UNLOAD. Today UNLOAD gives object (date).
  • The fetch methods return date for date, and None for NULL timestamp and date values. Today they return Timestamp, and NaT or nan.

Each change keeps reads vectorized and is measured for elapsed time and peak RSS. execute() options and custom converters keep their documented precedence. UNLOAD timestamp is tracked in #1214.

Activity

  1. laughingman7743 commented on Oct 16, 2026

    @laughingman7743
    MemberAuthor

    The conformance tests in #1226 found more cases for this issue with mixed columns (live Athena output, pandas 3.0.6). They are strict xfails that reference this issue:

    • A timestamp column whose text has 7 or more fractional digits is str when the column also holds values outside the datetime64[ns] range, such as years 1 and 9999. Chunked reads give str, object, or datetime64[ns] chunks, and the [ns] chunks keep nanoseconds instead of truncating to microseconds.
    • With engine="pyarrow", a timestamp(0) column is datetime64[s].
    • The fetch methods return NaT, or nan for a str column, instead of None for NULL timestamp and date values. A timestamp with time zone column whose values share one zone returns NaT too.
    • PandasCursor's conversion of local times without one instant (Define time zone conversion for values whose zone cannot be represented #1220) is expected with the vectorized check of this issue.
  2. changed the title [-]Make temporal dtypes depend only on the Athena type[/-] [+]Make PandasCursor's temporal dtypes and fetched types depend only on the Athena type[/+] on Oct 17, 2026
  3. laughingman7743 commented on Oct 18, 2026

    @laughingman7743
    MemberAuthor

    A fact for the timestamp item, measured with pandas 3.0.6 and pyarrow 26.0.0 at 3a41a84. With engine="pyarrow", the unit of a timestamp column depends on whether the values have a fraction, not on its length: a result file of 100 bytes or more, which PyAthena reads with its own PyArrow reader, gives datetime64[ns] for any fraction of 1 to 9 digits. The c and python engines give datetime64[us] for up to six digits and datetime64[ns] for nine. Athena writes TIMESTAMP values with three fractional digits, so with engine="pyarrow", a timestamp column of a real result is datetime64[ns].

    Text in the result file engine="pyarrow" engine="c" and "python"
    2024-01-01 00:00:00 datetime64[s] datetime64[us]
    2024-01-01 00:00:00.000 datetime64[ns] datetime64[us]
    2024-01-01 00:00:00.123 datetime64[ns] datetime64[us]
    2024-01-01 00:00:00.123456 datetime64[ns] datetime64[us]
    2024-01-01 00:00:00.123456789 datetime64[ns] datetime64[ns]

    Against Athena, SELECT TIMESTAMP '2024-01-01 00:00:00.123' AS t, CAST(NULL AS TIMESTAMP) AS t_null, rpad('x', 120, 'x') AS p read with PandasCursor gives t as datetime64[ns] with engine="pyarrow" and datetime64[us] with engine="c"; t_null is datetime64[s] with both. The table rows were measured offline through AthenaPandasResultSet over local result files (the _local_result_set() helper of #1256).

  4. 3 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions