Skip to content
26 changes: 26 additions & 0 deletions cpp/src/arrow/python/datetime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,32 @@ Result<std::string> TzinfoToString(PyObject* tzinfo) {
return result;
}

// try to look up key attribute
// in case of zoneinfo object
if (PyObject_HasAttrString(tzinfo, "key")) {
OwnedRef key(PyObject_GetAttrString(tzinfo, "key"));
RETURN_IF_PYERROR();
std::string result;
RETURN_NOT_OK(internal::PyUnicode_AsStdString(key.obj(), &result));
return result;
}

// try to look up _filename attribute
// in case of dateutil.tz object
if (PyObject_HasAttrString(tzinfo, "_filename")) {
OwnedRef _filename(PyObject_GetAttrString(tzinfo, "_filename"));
RETURN_IF_PYERROR();
std::string result;
RETURN_NOT_OK(internal::PyUnicode_AsStdString(_filename.obj(), &result));
// _filename returns a full path in general ('/usr/share/zoneinfo/Europe/Paris')
// or POSIX name on Windows ('Europe/Paris') - we need a substring in first case
std::size_t pos = result.find("zoneinfo/");
if (pos != std::string::npos) {
return result.substr(pos + 9);
}
return result;
}

// attempt to call tzinfo.tzname(None)
OwnedRef tzname_object(PyObject_CallMethod(tzinfo, "tzname", "O", Py_None));
RETURN_IF_PYERROR();
Expand Down
19 changes: 19 additions & 0 deletions python/pyarrow/tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,25 @@ def test_tzinfo_to_string(tz, expected):
assert pa.lib.tzinfo_to_string(tz) == expected


def test_dateutil_tzinfo_to_string():
pytest.importorskip("dateutil")
import dateutil.tz

tz = dateutil.tz.UTC
assert pa.lib.tzinfo_to_string(tz) == 'UTC'
tz = dateutil.tz.gettz('Europe/Paris')
assert pa.lib.tzinfo_to_string(tz) == 'Europe/Paris'


def test_zoneinfo_tzinfo_to_string():
zoneinfo = pytest.importorskip('zoneinfo')

tz = zoneinfo.ZoneInfo('UTC')
assert pa.lib.tzinfo_to_string(tz) == 'UTC'
tz = zoneinfo.ZoneInfo('Europe/Paris')
assert pa.lib.tzinfo_to_string(tz) == 'Europe/Paris'


def test_tzinfo_to_string_errors():
msg = "Not an instance of datetime.tzinfo"
with pytest.raises(TypeError):
Expand Down