Repository: duckdb/duckdb
File: tools/pythonpkg/src/native/python_objects.cpp (C++)

Code before:
	case LogicalTypeId::FLOAT:
		return py::cast(val.GetValue<float>());
	case LogicalTypeId::DOUBLE:
		return py::cast(val.GetValue<double>());
	case LogicalTypeId::DECIMAL: {
		return import_cache.decimal().Decimal()(val.ToString());
	}
	case LogicalTypeId::ENUM:
		return py::cast(EnumType::GetValue(val));
	case LogicalTypeId::VARCHAR:
		return py::cast(StringValue::Get(val));
	case LogicalTypeId::BLOB:
		return py::bytes(StringValue::Get(val));
	case LogicalTypeId::BIT:
		return py::cast(Bit::ToString(StringValue::Get(val)));
	case LogicalTypeId::TIMESTAMP:
	case LogicalTypeId::TIMESTAMP_MS:
	case LogicalTypeId::TIMESTAMP_NS:
	case LogicalTypeId::TIMESTAMP_SEC:
	case LogicalTypeId::TIMESTAMP_TZ: {
		D_ASSERT(type.InternalType() == PhysicalType::INT64);
		auto timestamp = val.GetValueUnsafe<timestamp_t>();

		InfinityType infinity = InfinityType::NONE;
		if (type.id() == LogicalTypeId::TIMESTAMP_MS) {
			timestamp = Timestamp::FromEpochMs(timestamp.value);
			infinity = GetTimestampInfinityType<timestamp_ms_t>(timestamp);
		} else if (type.id() == LogicalTypeId::TIMESTAMP_NS) {
			timestamp = Timestamp::FromEpochNanoSeconds(timestamp.value);
			infinity = GetTimestampInfinityType<timestamp_ns_t>(timestamp);
		} else if (type.id() == LogicalTypeId::TIMESTAMP_SEC) {
			timestamp = Timestamp::FromEpochSeconds(timestamp.value);
			infinity = GetTimestampInfinityType<timestamp_sec_t>(timestamp);
		} else {
			infinity = GetTimestampInfinityType<timestamp_t>(timestamp);
		}

		// Deal with infinity
		switch (infinity) {
		case InfinityType::POSITIVE: {
			return py::module::import("datetime").attr("datetime").attr("max");
		}
		case InfinityType::NEGATIVE: {
			return py::module::import("datetime").attr("datetime").attr("min");
		}
		case InfinityType::NONE:
			break;
		}
		int32_t year, month, day, hour, min, sec, micros;
		date_t date;
		dtime_t time;

Review comment (bug):
I'm slightly concerned with the existing code that we can overflow Python's more limited date range. Is that handled elsewhere?

Code after:
		return py::cast(val.GetValue<float>());
	case LogicalTypeId::DOUBLE:
		return py::cast(val.GetValue<double>());
	case LogicalTypeId::DECIMAL: {
		return import_cache.decimal().Decimal()(val.ToString());
	}
	case LogicalTypeId::ENUM:
		return py::cast(EnumType::GetValue(val));
	case LogicalTypeId::UNION: {
		return PythonObject::FromValue(UnionValue::GetValue(val), UnionValue::GetType(val));
	}
	case LogicalTypeId::VARCHAR:
		return py::cast(StringValue::Get(val));
	case LogicalTypeId::BLOB:
		return py::bytes(StringValue::Get(val));
	case LogicalTypeId::BIT:
		return py::cast(Bit::ToString(StringValue::Get(val)));
	case LogicalTypeId::TIMESTAMP:
	case LogicalTypeId::TIMESTAMP_MS:
	case LogicalTypeId::TIMESTAMP_NS:
	case LogicalTypeId::TIMESTAMP_SEC:
	case LogicalTypeId::TIMESTAMP_TZ: {
		D_ASSERT(type.InternalType() == PhysicalType::INT64);
		auto timestamp = val.GetValueUnsafe<timestamp_t>();

		InfinityType infinity = InfinityType::NONE;
		if (type.id() == LogicalTypeId::TIMESTAMP_MS) {
			timestamp = Timestamp::FromEpochMs(timestamp.value);
		} else if (type.id() == LogicalTypeId::TIMESTAMP_NS) {
			timestamp = Timestamp::FromEpochNanoSeconds(timestamp.value);
		} else if (type.id() == LogicalTypeId::TIMESTAMP_SEC) {
			timestamp = Timestamp::FromEpochSeconds(timestamp.value);
		}
		infinity = GetTimestampInfinityType(timestamp);

		// Deal with infinity
		switch (infinity) {
		case InfinityType::POSITIVE: {
			return py::reinterpret_borrow<py::object>(import_cache.datetime().datetime.max());
		}
		case InfinityType::NEGATIVE: {
			return py::reinterpret_borrow<py::object>(import_cache.datetime().datetime.min());
		}
		case InfinityType::NONE:
			break;
		}
		int32_t year, month, day, hour, min, sec, micros;
		date_t date;
		dtime_t time;
		Timestamp::Convert(timestamp, date, time);
		Date::Convert(date, year, month, day);