Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARROW-16547: [Python] to_pandas fails with FixedOffset timezones when timestamp_as_object is used #14448

Merged
merged 11 commits into from Oct 27, 2022
14 changes: 13 additions & 1 deletion python/pyarrow/src/arrow/python/arrow_to_pandas.cc
Expand Up @@ -1074,11 +1074,23 @@ struct ObjectWriterVisitor {
auto ConvertTimezoneAware = [&](typename Type::c_type value, PyObject** out) {
PyObject* naive_datetime;
RETURN_NOT_OK(ConvertTimezoneNaive(value, &naive_datetime));

// convert the timezone naive datetime object to timezone aware
AlenkaF marked this conversation as resolved.
Show resolved Hide resolved
*out = PyObject_CallMethod(tzinfo.obj(), "fromutc", "O", naive_datetime);
// two step conversion of the datetime mimics Python's code:
// dt.replace(tzinfo=datetime.timezone.utc).astimezone(tzinfo)
// first step: replacing timezone with timezone.utc (replace method)
OwnedRef args(PyTuple_New(0));
OwnedRef keywords(PyDict_New());
PyDict_SetItemString(keywords.obj(), "tzinfo", PyDateTime_TimeZone_UTC);
OwnedRef naive_datetime_replace(PyObject_GetAttrString(naive_datetime, "replace"));
OwnedRef datetime_utc(PyObject_Call(naive_datetime_replace.obj(), args.obj(), keywords.obj()));
// second step: adjust the datetime to tzinfo timezone (astimezone method)
*out = PyObject_CallMethod(datetime_utc.obj(), "astimezone", "O", tzinfo.obj());

// the timezone naive object is no longer required
Py_DECREF(naive_datetime);
RETURN_IF_PYERROR();

return Status::OK();
};

Expand Down
12 changes: 12 additions & 0 deletions python/pyarrow/tests/test_pandas.py
Expand Up @@ -4472,6 +4472,18 @@ def test_timestamp_as_object_non_nanosecond(resolution, tz, dt):
assert result[0] == expected


def test_timestamp_as_object_fixed_offset():
# ARROW-16547 to_pandas with timestamp_as_object=True and FixedOffset
pytz = pytest.importorskip("pytz")
import datetime
timezone = pytz.FixedOffset(120)
dt = timezone.localize(datetime.datetime(2022, 5, 12, 16, 57))

table = pa.table({"timestamp_col": pa.array([dt])})
result = table.to_pandas(timestamp_as_object=True)
assert pa.table(result) == table


def test_threaded_pandas_import():
invoke_script("pandas_threaded_import.py")

Expand Down