I was trying to generate a Report using Export to Excell, PDF, TextFile. Well I am doing this in MVC. I have a class which I named SPBatch (which is the exact name of my Stored
try with
dt.Columns.Add(pi.Name, Nullable.GetUnderlyingType(
            pi.PropertyType) ?? pi.PropertyType);
I would search for nullable and replace it with a string which can be null unlike a DateTime.
foreach (PropertyInfo pi in properties)
{
    if (pi.PropertyType.Name.Contains("Nullable"))
       myDataType = typeof(String);
    else
       myDataType = pi.PropertyType;
}
Here is a complete version:
private DataTable CreateDataTable(PropertyInfo[] properties)
{
    DataTable dt = new DataTable();
    DataColumn dc = null;
    foreach (PropertyInfo pi in properties)
    {
        dc = new DataColumn();
        dc.ColumnName = pi.Name;
        if (pi.PropertyType.Name.Contains("Nullable"))
            dc.DataType = typeof(String);
        else
            dc.DataType = pi.PropertyType;
        // dc.DataType = pi.PropertyType;
        dt.Columns.Add(dc);
    }
    return dt;
}
Thanks to a C# version of a generating a datatable and some hacking around, I can offer this answer in VB - I put it on here because I've just had a lot of hassle wanting to get a filterable dataset from a stored proc whilst using a simple datalayer. I hope it helps someone else!
Note: The use case is where you wish to use BindingSource.Filter = "some query string":
Imports System.Reflection
Public Module Extenders
<System.Runtime.CompilerServices.Extension>
Public Function ToDataTable(Of T)(collection As IEnumerable(Of T), tableName As String) As DataTable
    Dim tbl As DataTable = ToDataTable(collection)
    tbl.TableName = tableName
    Return tbl
End Function
<System.Runtime.CompilerServices.Extension>
Public Function ToDataTable(Of T)(collection As IEnumerable(Of T)) As DataTable
    Dim dt As New DataTable()
    Dim tt As Type = GetType(T)
    Dim pia As PropertyInfo() = tt.GetProperties()
    'Create the columns in the DataTable
    For Each pi As PropertyInfo In pia
        Dim a = 
If(Nullable.GetUnderlyingType(pi.PropertyType), pi.PropertyType)
        dt.Columns.Add(pi.Name, If(Nullable.GetUnderlyingType(pi.PropertyType), pi.PropertyType))
    Next
    'Populate the table
    For Each item As T In collection
        Dim dr As DataRow = dt.NewRow()
        dr.BeginEdit()
        For Each pi As PropertyInfo In pia
            dr(pi.Name) = If(Nullable.GetUnderlyingType(pi.PropertyType) Is GetType(DateTime), DBNull.Value, pi.GetValue(item, Nothing))
        Next
        dr.EndEdit()
        dt.Rows.Add(dr)
    Next
    Return dt
End Function
End Module
1) Define This Extensions as Below
public static class ListExtensions
    {
        public static DataTable ToDataTable<T>(this List<T> list)
        {
            DataTable table = new DataTable(typeof(T).Name);
            //Get Properites of List Fiels
            PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
            //Create Columns as Fields of List
            foreach (PropertyInfo propertyInfo in props)
            {
                var column = new DataColumn
                {
                    ColumnName = propertyInfo.Name,
                    DataType = propertyInfo.PropertyType.Name.Contains("Nullable") ? typeof(string) : propertyInfo.PropertyType
                };
                table.Columns.Add(column);
            }
            //Fill DataTable with Rows of List
            foreach (var item in list)
            {
                var values = new object[props.Length];
                for (var i = 0; i < props.Length; i++)
                {
                    values[i] = props[i].GetValue(item, null);
                }
                table.Rows.Add(values);
            }
            return table;
        }
    }
2) Call Extensions Method as Below where [_lstOperationDetails] is List that we want to convert it from List to DataTable
DataTable operationDetails = _lstOperationDetails.ToDataTable();