diff --git a/cpp/src/arrow/python/datetime.cc b/cpp/src/arrow/python/datetime.cc index 8c954998f0e..89d92f101c0 100644 --- a/cpp/src/arrow/python/datetime.cc +++ b/cpp/src/arrow/python/datetime.cc @@ -470,6 +470,32 @@ Result 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(); diff --git a/python/pyarrow/tests/test_types.py b/python/pyarrow/tests/test_types.py index 07715b985bd..a46049f9a0a 100644 --- a/python/pyarrow/tests/test_types.py +++ b/python/pyarrow/tests/test_types.py @@ -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):