[ 
https://issues.apache.org/jira/browse/SPARK-60499?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

ASF GitHub Bot updated SPARK-60499:
-----------------------------------
    Labels: pull-request-available  (was: )

> toPandas with Arrow fails or returns wrong values for timestamps outside the 
> datetime64[ns] range with pandas 3
> ---------------------------------------------------------------------------------------------------------------
>
>                 Key: SPARK-60499
>                 URL: https://issues.apache.org/jira/browse/SPARK-60499
>             Project: Spark
>          Issue Type: Sub-task
>          Components: PySpark
>    Affects Versions: 5.0.0
>            Reporter: Shuheng Ma
>            Priority: Major
>              Labels: pull-request-available
>
> h3. Description
> With pandas 3 and Arrow enabled (the default since Spark 4.2), {{toPandas()}} 
> fails on timestamps after 2262-04-11, such as the common sentinel 
> {{9999-12-31}}. Values that fit in {{datetime64\[ns\]}} as UTC but not as 
> local time, such as {{1677-09-21 00:00}} in America/Los_Angeles, come back 
> silently wrong. The Arrow path still forces every timestamp to nanoseconds, 
> while the non-Arrow path already returns {{datetime64\[us\]}} on pandas 3 and 
> converts the same values correctly. pandas 3 isn't officially supported yet 
> (SPARK-57974 caps pandas below 3.0.0), so I'm filing this under SPARK-55139.
> h3. Reproducer
> Run line by line in the pyspark shell (Spark master eacf31b, pandas 3.0.6, 
> pyarrow 26.0.0, classic):
> {code:python}
> spark.conf.set("spark.sql.session.timeZone", "America/Los_Angeles")
> df = spark.sql(
>     "SELECT TIMESTAMP'9999-12-31 00:00:00' AS ts, TIMESTAMP_NTZ'9999-12-31 
> 00:00:00' AS ts_ntz"
> )
> df2 = spark.sql("SELECT TIMESTAMP'1677-09-21 00:00:00' AS ts")
> spark.conf.set("spark.sql.execution.arrow.pyspark.enabled", "false")
> df.toPandas()   # 9999-12-31 in both columns, dtype datetime64[us]
> df2.toPandas()  # 1677-09-21
> spark.conf.set("spark.sql.execution.arrow.pyspark.enabled", "true")
> df2.toPandas()  # 2262-04-11 23:34:33.709551 (wrong, no error)
> df.toPandas()
> # pyarrow.lib.ArrowInvalid: Casting from timestamp[us, 
> tz=America/Los_Angeles] to timestamp[ns]
> # would result in out of bounds timestamp: 253402243200000000
> {code}
> With Spark Connect, {{toPandas()}} always goes through Arrow, so it fails on 
> {{9999-12-31}} and returns the wrong {{1677-09-21}} value whatever 
> {{spark.sql.execution.arrow.pyspark.enabled}} is set to.
> h3. Cause
> {{_convert_arrow_table_to_pandas}} in 
> [python/pyspark/sql/pandas/conversion.py|https://github.com/apache/spark/blob/eacf31bf9a429d28e34ebe20ad7c7444c3d026bd/python/pyspark/sql/pandas/conversion.py#L251]
>  always passes {{coerce_temporal_nanoseconds=True}} to pyarrow. Both classic 
> and Connect {{toPandas()}} use it.
> * The flag was added in SPARK-45143 to keep the nanosecond output after 
> pyarrow 13.
> * Since SPARK-55843, {{_to_corrected_pandas_type}} maps TimestampType and 
> TimestampNTZType to {{datetime64\[us\]}} on pandas 3.
> * Since SPARK-56310, the TimestampType converter casts back to that dtype 
> after the time zone conversion.
> So on pandas 3 the values go us -> ns -> us. The ns step fails for values 
> outside the ns range, and values near 1677-09-21 can wrap around silently 
> during the time zone conversion.
> h3. Suggested fix
> Only pass {{coerce_temporal_nanoseconds=True}} when pandas < 3, matching 
> {{_to_corrected_pandas_type}}. In-range values are unchanged, because the 
> result was already {{datetime64\[us\]}} on pandas 3. Nothing changes on 
> pandas < 3: the output stays {{datetime64\[ns\]}}. As a side effect, 
> DayTimeIntervalType values beyond about 292 years also come back correct on 
> pandas 3. Today they silently overflow on the Arrow path.
> One edge remains. On pandas 3, TimestampType values before 1677-09-21 (UTC) 
> in a zone with local mean time, such as America/Los_Angeles, come back a few 
> minutes off after the fix: {{0001-01-01 00:00}} becomes {{0000-12-31 
> 23:52:58}}. This is because pandas' {{tz_convert}} uses -8:00 there instead 
> of -7:52:58. Today these values fail on the Arrow path, and the non-Arrow 
> path raises ValueError for them.
> I have a fix with tests ready and will open a PR shortly.
> Co-developed with Claude Code (Claude Opus 5.5): the investigation, the 
> reproducer and this description.
> Generated-by: Claude Code (Claude Opus 5.5)



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to