Repository navigation
Conversation
|
Hi @zhengruifeng @gaogaotiantian, could you take a look when you have a moment? This follows SPARK-55843 (#54629) and SPARK-56310 (#55118), which moved One question where I wasn't sure what you'd prefer: pandas UDF / (The pandas < 3 question, about a clearer error for out-of-range timestamps, is on the JIRA.) I'll follow whichever you think is best. Thanks for your time! |
…the datetime64[ns] range on pandas 3 Only coerce timestamps to nanoseconds in _convert_arrow_table_to_pandas when pandas < 3, matching _to_corrected_pandas_type. On pandas 3 the Arrow path now returns the same values as the non-Arrow path for timestamps outside the datetime64[ns] range, such as 9999-12-31. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What changes were proposed in this pull request?
Fixes SPARK-60499, a sub-task of SPARK-55139 (Support Pandas 3).
Fix:
_convert_arrow_table_to_pandaspassescoerce_temporal_nanoseconds=Trueto pyarrow only when pandas < 3, the same version check_to_corrected_pandas_typeuses to mapTimestampTypeandTimestampNTZTypetodatetime64[ns](pandas < 3) ordatetime64[us](pandas 3). Both classictoPandas()and Spark ConnecttoPandas()call this function, so both are fixed.test_toPandas_timestamp_out_of_ns_rangeinArrowTestsMixin, with its Connect parity override.Why are the changes needed?
With pandas 3 and Arrow enabled (the default since Spark 4.2),
toPandas()fails on timestamps after 2262-04-11, such as the common sentinel9999-12-31. Values that fit indatetime64[ns]as UTC but not as local time, such as1677-09-21 00:00in America/Los_Angeles, come back silently wrong. The non-Arrow path already returnsdatetime64[us]on pandas 3 and converts the same values correctly.Spark Connect always goes through Arrow, so it fails on
9999-12-31and returns the wrong1677-09-21value whateverspark.sql.execution.arrow.pyspark.enabledis set to.When it started:
coerce_temporal_nanoseconds=Truewas added in SPARK-45143 (#42920, 4.0.0) to keep the nanosecond output after pyarrow 13 started returning the original unit.TimestampTypeandTimestampNTZTypetodatetime64[us]on pandas 3, and SPARK-56310 (4.2.0) made theTimestampTypeconverter cast back to that dtype after the time zone conversion. Since then, on pandas 3 the Arrow path goes us -> ns -> us. The ns step fails for values outside the ns range, and values near 1677-09-21 can wrap around during the time zone conversion.Reports from users:
ArrowInvalidwith Arrow (one of them on9999-12-31) andOutOfBoundsDatetimewithout Arrow. The links are in the JIRA comment.What goes wrong:
pandas/conversion.py,_convert_arrow_table_to_pandassetscoerce_temporal_nanoseconds=Truefor every pandas version, so pyarrow casts every timestamp to nanoseconds before Spark's converters run.Does this PR introduce any user-facing change?
Yes, on pandas 3 only. pandas 3 isn't officially supported in any release yet, so this only matters for users who already run pandas 3.
Behavior change:
toPandas()(classic and Connect) now returns timestamps after 2262-04-11, such as9999-12-31, instead of raisingArrowInvalid. Values like1677-09-21 00:00in America/Los_Angeles are now correct instead of silently wrong. Both now match the non-Arrow path.DayTimeIntervalTypevalues beyond about 292 years (for exampleINTERVAL '365000' DAY) are now correct. Before, the Arrow path silently returned a wrong value (-62008 days +00:50:52.580896).datetime64[us]on pandas 3.Not covered:
datetime64[ns]can't hold these values, so9999-12-31still fails on both paths there, and with Arrow1677-09-21 00:00in America/Los_Angeles still comes back wrong. I asked on the JIRA whether a clearer error would be welcome.applyInPandasandmapInPandasinputs still coerce timestamps to nanoseconds on pandas 3, inArrowArrayConversion.preprocess_timeandArrowToPandasConversion. Changing those changes the dtype UDFs receive, so I left them out.TimestampTypevalues before 1677-09-21 (UTC) in a zone with local mean time, such as America/Los_Angeles, now come back a few minutes off with Arrow:0001-01-01 00:00becomes0000-12-31 23:52:58. pandas'tz_convertuses -8:00 there instead of -7:52:58. Before this PR these values raisedArrowInvalid, and the non-Arrow path raisesValueErrorfor them.How was this patch tested?
Tests:
test_toPandas_timestamp_out_of_ns_rangeconverts9999-12-31and1677-09-21in America/Los_Angeles, asTimestampTypeandTimestampNTZType, with Arrow enabled and disabled, and compares with the expected values. The Connect parity override runs it with Arrow, as the othertoPandasparity tests do. It is skipped on pandas < 3, where nothing changes.ArrowInvalid: Casting from timestamp[us, tz=America/Los_Angeles] to timestamp[ns] would result in out of bounds timestamp: 253402243200000000.build_python_3.12_pandas_3.yml) will run it after merge. I ran it locally on pandas 3.0.6 (pyarrow 26.0.0), with the machine time zone set to America/Chicago, Pacific/Kiritimati, Etc/GMT+12 and Asia/Tokyo.structHandlingModevalues), nanosecond timestamp types, empty DataFrames andselfDestruct. They are identical.Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 5.5)
Co-developed with Claude Code (Claude Opus 5.5): the investigation, the fix, the tests and this description. The checks above were run locally.