How to set Column Type when using EPPlus

Solution 1:

You do need the DataTable column to have the right type but you also need to modify the column or cell's Style.Numberformat.Format property.

Say you have an ExcelWorksheet named ws:

ws.Column(1).Style.Numberformat.Format  = "yyyy-mm-dd"; 
//OR "yyyy-mm-dd h:mm" if you want to include the time!

Solution 2:

Based on this discussion (epplus.codeplex.com/discussions/349927) you can also set column format to date.

worksheet_1.Cells[row, 3].Style.Numberformat.Format = DateTimeFormatInfo.CurrentInfo.ShortDatePattern;

Solution 3:

If your columns are likely to move around (as we know end-users tend to be fickle) or you just have many date columns scattered across your spreadsheet, it would be helpful to write something a little more generic. Here is what I just wrote. It finds the position of all DateTime types in my POCO and creates a list that it then uses to set the column formatting. Remember data tables are zero based and Excel is not.

        ws.Cells.LoadFromDataTable(tbl, true);
        var dPos = new List<int>();
        for (var i = 0; i < tbl.Columns.Count; i++)
            if (tbl.Columns[i].DataType.Name.Equals("DateTime"))
                dPos.Add(i);
        foreach (var pos in dPos)
        {
            ws.Column(pos+1).Style.Numberformat.Format = "mm/dd/yyyy hh:mm:ss AM/PM";
        }

If you are doing more than one datatable, you'll probably want to refactor it off into a function.

And here is a freebie... I can't take credit for this code. It takes a POCO list and turns it into a data table. It has made my life easier on a number of occasions having it in my 'toolkit'. Enjoy.

        public DataTable ConvertToDataTable<T>(IList<T> data)
    {
        var properties =
           TypeDescriptor.GetProperties(typeof(T));
        var table = new DataTable();
        foreach (PropertyDescriptor prop in properties)
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        foreach (T item in data)
        {
            var row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            table.Rows.Add(row);
        }
        return table;
    }

Solution 4:

Here's a nice C# extension method to help load from collection with headers and the proper date formatting:

(Decorate your properties with Description attributes for the column headings)

public static class EpPlusExtensions
{
    public static void Load<T>(this ExcelWorksheet worksheet, IEnumerable<T> collection)
    {
        worksheet.Cells["A1"].LoadFromCollection(collection, true);

        var properties = typeof(T).GetProperties();

        for (var i = 0; i < properties.Length; i++)
        {
            if (new []{typeof(DateTime), typeof(DateTime?)}.Contains(properties[i].PropertyType)) 
            {
                worksheet.Column(i + 1).Style.Numberformat.Format = "m/d/yyyy";
            }
        }
    } 
}