Using Cells.ImportData to import and format empty DateTime columns

I have a requirement to quickly load a DataTable into an Excel sheet, where cells should automatically format to correspond to the DataTable’s column types. This is particularly important for DateTime columns.

This works fine, cells with DateTime values becomes formatted as “Date” in Excel.

But, if the value being imported is null (or System.DBNull actually, since DataTable uses this to represent null values), the cell remains formatted as “General”.

Here’s what I tried:

  • A custom ICellsDataTable interface (to explictly return null for DBNull values)
  • NumberFormats collection, to explicitly specify the number format for the DateTime column to “YYYY-MM-DD”.

But nothing works. I know I can write code that iterates over the cells that should be formatted as Date, but that is too slow and clunky.

Is there any other way to get empty data (DateTime) to become formatted as “Date” when importing data using Aspose?

Using Aspose.Cells for .NET, 25.10.0

Here’s the code:

using System.Data;
using System.Diagnostics;
using Aspose.Cells;
using DateTimeFormat;

class Program
{
    static void Main()
    {
        // Create a sample DataTable
        var table = new DataTable("MyTable");
        table.Columns.Add("ColInt", typeof(int));
        table.Columns.Add("ColString", typeof(string));
        table.Columns.Add("ColDateTime", typeof(DateTime));

        table.Rows.Add(1, "Hello", DateTime.UtcNow.Date.AddHours(9));
        table.Rows.Add(2, "World", DateTime.UtcNow.Date.AddHours(10));
        table.Rows.Add(3, null, null);

        // Create a new Workbook and import the DataTable
        var wb = new Workbook();
        var ws = wb.Worksheets[0];

        var opts = new ImportTableOptions
        {
            IsFieldNameShown = true,
            NumberFormats = new string[] { null, null, "YYYY-MM-DD" },
            ConvertNumericData = false,
        };

        ws.Cells.ImportData(table, 0, 0, opts);
        ws.Cells.ImportData(new CellsDataTable(table), 10, 0, opts);
        ws.AutoFitColumns();

        // Save with unique name
        var fileName = $"ImportData_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx";
        var fullPath = Path.Combine(Directory.GetCurrentDirectory(), fileName);
        wb.Save(fullPath);

        Console.WriteLine($"Saved: {fullPath}");

        // Try to open the file in Excel
        try
        {
            Process.Start(new ProcessStartInfo(fullPath) { UseShellExecute = true });

            Console.WriteLine("Opening in Excel (if installed)...");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Could not open automatically: {ex.Message}");
        }
    }
}

And the ICellsDataTable implementation:

using Aspose.Cells;
using System.Data;

namespace DateTimeFormat
{
    internal class CellsDataTable : ICellsDataTable
    {
        private readonly DataTable tbl;
        private int currentRowIndex = -1;

        public CellsDataTable(DataTable tbl)
        {
            this.tbl = tbl;
        }

        public object this[int columnIndex]
        {
            get
            {
                object dbValue = tbl.Rows[currentRowIndex][columnIndex];
                if (dbValue.GetType() == typeof(DBNull) && tbl.Columns[columnIndex].DataType == typeof(System.DateTime))
                {
                    return null;   
                }
                else
                {
                    return dbValue;
                }
            }
        }

        public object this[string columnName]
        {
            get
            {
                return tbl.Rows[currentRowIndex][columnName];
            }
        }

        public string[] Columns => tbl.Columns.Cast<DataColumn>().Select(c => c.ColumnName).ToArray();

        public int Count => tbl.Rows.Count;

        public void BeforeFirst() => currentRowIndex = -1;

        public bool Next() => ++currentRowIndex < tbl.Rows.Count;
    }
}

@gunman69

Problem recap

  • Cells.ImportData (or ImportDataTable) formats a DateTime column as Date when the cell contains a real DateTime value.
  • When the column contains DBNull / null, the imported cell is left with the General number format.

Aspose .Cells does not automatically apply a number format to a cell that has no value.
The only way to make those empty cells behave as Date cells is to assign a date‑style to the cells (or the whole column) yourself after the import.
Doing this is fast – you apply the style to a whole column (or range) in a single call, not by iterating each cell.

Below is a complete, self‑contained example that shows:

  1. Importing the DataTable (your current code works fine).
  2. Creating a date style (Number = 14 – built‑in short date, or a custom format such as "yyyy‑mm‑dd").
  3. Applying that style to the whole column (including empty cells) with a StyleFlag.
using System;
using System.Data;
using System.IO;
using Aspose.Cells;

namespace DateTimeFormatDemo
{
    class Program
    {
        static void Main()
        {
            // ---------- 1. Build sample DataTable ----------
            var table = new DataTable("MyTable");
            table.Columns.Add("ColInt", typeof(int));
            table.Columns.Add("ColString", typeof(string));
            table.Columns.Add("ColDateTime", typeof(DateTime));

            table.Rows.Add(1, "Hello", DateTime.UtcNow.Date.AddHours(9));
            table.Rows.Add(2, "World", DateTime.UtcNow.Date.AddHours(10));
            table.Rows.Add(3, null, null);               // <-- DBNull for DateTime

            // ---------- 2. Import the table ----------
            var wb = new Workbook();
            var ws = wb.Worksheets[0];

            var importOpts = new ImportTableOptions
            {
                IsFieldNameShown = true,
                // we do NOT need NumberFormats here – we will apply format later
                ConvertNumericData = false
            };

            ws.Cells.ImportData(table, 0, 0, importOpts);
            ws.AutoFitColumns();

            // ---------- 3. Create a Date style ----------
            // You can use a built‑in format (e.g. Number = 14) or a custom one.
            Style dateStyle = wb.CreateStyle();
            // Built‑in short date format:
            // dateStyle.Number = 14;
            // Or a custom format:
            dateStyle.Custom = "yyyy-mm-dd";

            // ---------- 4. Apply the style to the whole column ----------
            // Column index of the DateTime column (0‑based)
            int dateColIdx = 2;

            // Create a flag that tells Aspose.Cells to change only the number format.
            StyleFlag flag = new StyleFlag { NumberFormat = true };

            // Apply to the **entire column**, including the header row (row 0).
            // The range covers every possible row: 0 – MaxRowCount‑1.
            int maxRows = ws.Cells.MaxDisplayRange.RowCount;   // or a large constant, e.g. 65535
            ws.Cells.CreateRange(0, dateColIdx, maxRows, 1).ApplyStyle(dateStyle, flag);

            // ---------- 5. Save ----------
            string fileName = $"ImportData_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx";
            wb.Save(fileName);
            Console.WriteLine($"Workbook saved to {Path.GetFullPath(fileName)}");
        }
    }
}

What the code does

Step Explanation
1‑2 Import the DataTable exactly as you already do. The date values get the Date format automatically; the null row stays General.
3 Build a Style object that contains the desired date format. You can use a built‑in format (Number = 14) or a custom string (Custom = "yyyy‑mm‑dd").
4 Use a StyleFlag with NumberFormat = true so that only the number format part of the style is changed. Apply the style to the whole column (CreateRange(...).ApplyStyle(...)). This operation touches all cells in the column in a single call, so it is very fast even for large worksheets. Empty cells inherit the date format, and any later values you write to those cells will be treated as dates automatically.
5 Save the workbook.

Why this works

  • ImportData does not know which format to apply to a cell that has no value – it simply leaves the default General format.
  • By assigning a date style to the entire column (or a specific range) after the import, you force every cell – populated or empty – to have the date number format.
  • The StyleFlag ensures that only the number‑format part is altered; all other cell attributes (font, alignment, etc.) remain unchanged.

Additional notes

Topic Details
Performance Applying a style to a column is O(1) – Aspose.Cells updates the column’s style internally; no per‑cell loop is required.
Multiple date columns Create a single Style (or several if you need different formats) and repeat the ApplyStyle call for each column index.
Using ImportDataTable The same approach works; you just call ws.Cells.ImportDataTable(table, 0, 0, importOpts); and then apply the column style.
Preserving existing formats If you need to keep other column styles (e.g., font colour) but only change the number format, the StyleFlag (NumberFormat = true) guarantees that only the format part is touched.
Custom culture‑independent format "yyyy-mm-dd" is a locale‑independent custom format that always shows the year‑month‑day order. Use "mm/dd/yyyy" or any other pattern if you prefer a different display.

TL;DR

  • ImportData cannot infer a date format for null cells.
  • After importing, apply a date style to the whole column (or a range) with a StyleFlag that changes only the number format.
  • This is a single‑call operation, fast, and works for any size of worksheet.

If you need further assistance—e.g., applying the style to a dynamic set of columns, or using a different built‑in date format—please let me know!

Reference:

Happy coding! :rocket:

@gunman69,

I tested and noticed the issue/behavior as you mentioned by using your sample code snippet. I found by using Cells.ImportData to import and format empty DateTime columns, the cells remain formatted as “General” instead of DateTime formatting.

We require thorough evaluation of the issue. We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): CELLSNET-59295

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.

Thanks, Amjad!

I did receive an AI-generated suggestion to solve the problem, by “manually” changing the format of the entire column(s) that the DateTime cells are part of (using ApplyStyle).

That would work for many cases, but it wouldn’t work for us, since we have multiple “regions” on the same sheet that we load with data that has different sets of columns. For instance, column “C” may be “Date” in some regions, but “Text” or “Number” in other regions.
So, we would have to find exactly which cells to format using ApplyStyle. That would hurt performance of course, but the code would also become really complex, since our code is highly dynamic. The code is not hard-coded for certain datatypes per columns, but that is configured dynamically by metadata.

A much better option would be if it becomes possible to return some value that represents a “null” DateTime value, which would generate an empty cell in Excel, formatted as Date. Since DateTime is a struct, that is not possibly directly, but perhaps using some kind of internal DateTimeObject class (which would be a reference class instead of a struct) could work.

Another option, I just realized, is that if Aspose would honour the NumberFormats even for null values, I could force certain columns to be formatted as date. That would be much easier.

@gunman69,

Since we just logged the ticket for it, so we request a little time to thoroughly evaluate the issue. We are hopeful to provide a resolution or alternative options to address it, ensuring that Cells.ImportData can import and format DateTime columns with empty or null data appropriately, so the cells are formatted with relevant DateTime formatting instead of “General”.

@gunman69
We have fixed this issue.
It will be included into the next version 25.11 which will be released the first half of this month.
If it’s released, you will be notified.

Wow, that’s great! May I ask how you have solved it? It’s not possible to deduce the datatype from the value since it is null, and there’s no thing as a ”null” DateTime struct. So, is it using NumberFormats, ie honoring NumberFornats also when the value is null?

@gunman69
We only can force setting number format when the number format is set, even if the value is null.

That sounds awesome. I realize NumberFormats is a string array. So there is no way of specifying any of the predefined formats, using the integer id (e.g. 14 for date): List of Supported Number Formats|Documentation
I guess that means that using NumberFormats, the format style in Excel will always become “Custom”, which is not ideal.

Maybe if NumberFormats was object[] with possible values null, int or string?

@gunman69
Thanks for your feedback and details. We will investigate your issue further and get back to you soon.

@gunman69
Our design philosophy is to minimize providing objects as parameters.
Objects can cause confusion for our clients.
We are considering providing a Style array as parameter, or adding ImportTableOptions.GetColumnStyle(int column) method to return a Style.

@gunman69
Or you can set number format to the first row of the range as the following :

 var opts = new ImportTableOptions
 {
     IsFieldNameShown = true,
    // NumberFormats = new string[] { null, null, "YYYY-MM-DD" },
     ConvertNumericData = false,
 };
// for(int i = 0; i < 3; i ++)
 {
     // Cell c = ws.Cells[0, i];
     Cell c = ws.Cells[0, 2];
     Style style = c.GetStyle(false);
     style.Number = 14;
     c.SetStyle(style);
 }

Hi again,

I totally agree that using “object[]” as parameter is not a good design, I suggested it as a way to solve the problem with minimal changes to the API.
A good design is also to have consistency, and it is a little inconsistent to provide “string[] NumberFormats” but not “Style[] NumberStyles” so that sounds like a good idea to add that :slight_smile:

To do SetStyle on all cells that require formatting, as suggested in the code snipper, is not feasible - we sometimes have hundreds of thousands of cells that would have to be accessed, and performance would be poor.

@gunman69,

Thanks for sharing your feedback.

As mentioned earlier, we are exploring the possibility of providing a Style array as a parameter or introducing the ImportTableOptions.GetColumnStyle(int column) method to return a Style. We will carefully assess the feasibility of each approach and will keep you updated on which way we go as we make progress.

@gunman69
1,We have created a ticket CELLSNET-59305 to support Style as param of ImportTableOptions.
2,

You just need to set the cells in the first row if ImportTableOptions.InsertRows is true( default).
We will auto apply the style of the first row to new inserted rows when importing data table.

@gunman69,

This is to inform you that your issue (Ticket ID: “CELLSNET-59305”) has been resolved. The fix/enhancement will be included in the upcoming release (Aspose.Cells v25.11), scheduled for release in the first half of November 2025 (approximately between the 10th and 15th). We will notify you again once the next version is available.