Excel 单元格中的 OpenXml 和日期格式

发布于 2024-11-07 23:48:15 字数 3605 浏览 4 评论 0原文

我正在尝试使用 OpenXML 创建 xlsx 格式的 Excel 文件,因为我需要在 Web 服务器上使用它。

我在表格中填写值没有任何问题;但是我正在努力在单元格中设置经典的日期格式。

下面使用 DocumentFormat.OpenXml 和 WindowsBase 引用进行快速测试。

class Program
{
    static void Main(string[] args)
    {
        BuildExel(@"C:\test.xlsx");
    }

    public static void BuildExel(string fileName)
    {
        using (SpreadsheetDocument myWorkbook =
               SpreadsheetDocument.Create(fileName,
               SpreadsheetDocumentType.Workbook))
        {
            // Workbook Part
            WorkbookPart workbookPart = myWorkbook.AddWorkbookPart();
            var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
            string relId = workbookPart.GetIdOfPart(worksheetPart);

            // File Version
            var fileVersion = new FileVersion { ApplicationName = "Microsoft Office Excel" };

            // Style Part
            WorkbookStylesPart wbsp = workbookPart.AddNewPart<WorkbookStylesPart>();
            wbsp.Stylesheet = CreateStylesheet();
            wbsp.Stylesheet.Save();

            // Sheets
            var sheets = new Sheets();
            var sheet = new Sheet { Name = "sheetName", SheetId = 1, Id = relId };
            sheets.Append(sheet);

            // Data
            SheetData sheetData = new SheetData(CreateSheetData1());

            // Add the parts to the workbook and save
            var workbook = new Workbook();
            workbook.Append(fileVersion);
            workbook.Append(sheets);
            var worksheet = new Worksheet();
            worksheet.Append(sheetData);
            worksheetPart.Worksheet = worksheet;
            worksheetPart.Worksheet.Save();
            myWorkbook.WorkbookPart.Workbook = workbook;
            myWorkbook.WorkbookPart.Workbook.Save();
            myWorkbook.Close();
        }
    }

    private static Stylesheet CreateStylesheet()
    {
        Stylesheet ss = new Stylesheet();

        var nfs = new NumberingFormats();
        var nformatDateTime = new NumberingFormat
        {
            NumberFormatId = UInt32Value.FromUInt32(1),
            FormatCode = StringValue.FromString("dd/mm/yyyy")
        };
        nfs.Append(nformatDateTime);
        ss.Append(nfs);

        return ss;
    }

    private static List<OpenXmlElement> CreateSheetData1()
    {
        List<OpenXmlElement> elements = new List<OpenXmlElement>();

        var row = new Row();

        // Line 1
        Cell[] cells = new Cell[2];

        Cell cell1 = new Cell();
        cell1.DataType = CellValues.InlineString;
        cell1.InlineString = new InlineString { Text = new Text { Text = "Daniel" } };
        cells[0] = cell1;

        Cell cell2 = new Cell();
        cell2.DataType = CellValues.Number;
        cell2.CellValue = new CellValue((50.5).ToString());
        cells[1] = cell2;

        row.Append(cells);
        elements.Add(row);

        // Line 2
        row = new Row();
        cells = new Cell[1];
        Cell cell3 = new Cell();
        cell3.DataType = CellValues.Date;
        cell3.CellValue = new CellValue(DateTime.Now.ToOADate().ToString());
        cell3.StyleIndex = 1; // <= here I try to apply the style...
        cells[0] = cell3;

        row.Append(cells);
        elements.Add(row);

        return elements;
    }

执行的代码创建 Excel 文档。但是,当我尝试打开文档时,我收到以下消息:“Excel 在“test.xlsx”中发现了无法读取的内容。您想恢复该工作簿的内容吗?如果您信任此工作簿的来源,请单击“是”。”

如果我删除该行:

cell3.StyleIndex = 1;

我可以打开文档,但日期如果未格式化,则仅显示日期编号。

感谢您帮助设置日期格式。

I am trying to create an Excel file in xlsx format using OpenXML because I need to use that on a web server.

I don’t have any problem to fill the values in the sheets; however I am struggling to set the classic Date format in a cell.

Below a quick test using DocumentFormat.OpenXml and WindowsBase references.

class Program
{
    static void Main(string[] args)
    {
        BuildExel(@"C:\test.xlsx");
    }

    public static void BuildExel(string fileName)
    {
        using (SpreadsheetDocument myWorkbook =
               SpreadsheetDocument.Create(fileName,
               SpreadsheetDocumentType.Workbook))
        {
            // Workbook Part
            WorkbookPart workbookPart = myWorkbook.AddWorkbookPart();
            var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
            string relId = workbookPart.GetIdOfPart(worksheetPart);

            // File Version
            var fileVersion = new FileVersion { ApplicationName = "Microsoft Office Excel" };

            // Style Part
            WorkbookStylesPart wbsp = workbookPart.AddNewPart<WorkbookStylesPart>();
            wbsp.Stylesheet = CreateStylesheet();
            wbsp.Stylesheet.Save();

            // Sheets
            var sheets = new Sheets();
            var sheet = new Sheet { Name = "sheetName", SheetId = 1, Id = relId };
            sheets.Append(sheet);

            // Data
            SheetData sheetData = new SheetData(CreateSheetData1());

            // Add the parts to the workbook and save
            var workbook = new Workbook();
            workbook.Append(fileVersion);
            workbook.Append(sheets);
            var worksheet = new Worksheet();
            worksheet.Append(sheetData);
            worksheetPart.Worksheet = worksheet;
            worksheetPart.Worksheet.Save();
            myWorkbook.WorkbookPart.Workbook = workbook;
            myWorkbook.WorkbookPart.Workbook.Save();
            myWorkbook.Close();
        }
    }

    private static Stylesheet CreateStylesheet()
    {
        Stylesheet ss = new Stylesheet();

        var nfs = new NumberingFormats();
        var nformatDateTime = new NumberingFormat
        {
            NumberFormatId = UInt32Value.FromUInt32(1),
            FormatCode = StringValue.FromString("dd/mm/yyyy")
        };
        nfs.Append(nformatDateTime);
        ss.Append(nfs);

        return ss;
    }

    private static List<OpenXmlElement> CreateSheetData1()
    {
        List<OpenXmlElement> elements = new List<OpenXmlElement>();

        var row = new Row();

        // Line 1
        Cell[] cells = new Cell[2];

        Cell cell1 = new Cell();
        cell1.DataType = CellValues.InlineString;
        cell1.InlineString = new InlineString { Text = new Text { Text = "Daniel" } };
        cells[0] = cell1;

        Cell cell2 = new Cell();
        cell2.DataType = CellValues.Number;
        cell2.CellValue = new CellValue((50.5).ToString());
        cells[1] = cell2;

        row.Append(cells);
        elements.Add(row);

        // Line 2
        row = new Row();
        cells = new Cell[1];
        Cell cell3 = new Cell();
        cell3.DataType = CellValues.Date;
        cell3.CellValue = new CellValue(DateTime.Now.ToOADate().ToString());
        cell3.StyleIndex = 1; // <= here I try to apply the style...
        cells[0] = cell3;

        row.Append(cells);
        elements.Add(row);

        return elements;
    }

The code executed creates the Excel document. However when I try to open the document, I receive this message: “Excel found unreadable content in 'test.xlsx'. Do you want to recover the contents of this workbook? If you trust the source of this workbook, click Yes.”

If I remove the row:

cell3.StyleIndex = 1;

I can open the document but the date if not formatted, only the number of the date appears.

Thank you for your help to format the date.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

っ左 2024-11-14 23:48:15

这个博客帮助了我:http:// /polymathprogrammer.com/2009/11/09/how-to-create-stylesheet-in-excel-open-xml/

我的问题是我想将 NumberingFormats 添加到样式表中,而不是完全添加新的样式表。如果你想做到这一点,请使用

Stylesheet.InsertAt<NumberingFormats>(new NumberingFormats(), 0);

而不是

Stylesheet.AppendChild<NumberingFormats>(new NumberingFormats(), 0);

惊喜,订单很重要。

This blog helped me: http://polymathprogrammer.com/2009/11/09/how-to-create-stylesheet-in-excel-open-xml/

My problem was that I wanted to add NumberingFormats to the stylesheet rather than adding a new stylesheet altogether. If you want to to that, use

Stylesheet.InsertAt<NumberingFormats>(new NumberingFormats(), 0);

rather than

Stylesheet.AppendChild<NumberingFormats>(new NumberingFormats(), 0);

surprise, order counts..

陌伤浅笑 2024-11-14 23:48:15

https://github.com/linedxml/linedxml 基本上是我认为的正确答案。

https://github.com/closedxml/closedxml is basically the correct answer I think.

堇年纸鸢 2024-11-14 23:48:15

另一个大投票: https://github.com/linedxml/latedxml

在尝试构建我的我从网络上散布的零碎信息(包括 StackOverFlow)中找到了自己的类,我找到了上面提到的库,并且很快就得到了一个功能齐全的 Excel 文件。

我将我的尝试粘贴在下面,以启发那些渴望完成它的人。它已部分完成,并且在日期和字符串单元格创建方面存在问题。

在尝试使用此类之前,请先下载 closeXML 并先尝试。

考虑一下你自己受到了警告。

    /// <summary>
    /// This class allows for the easy creation of a simple Excel document who's sole purpose is to contain some export data.
    /// The document is created using OpenXML.
    /// </summary>
    internal class SimpleExcelDocument : IDisposable
    {
        SheetData sheetData;

        /// <summary>
        /// Constructor is nothing special because the work is done at export.
        /// </summary>
        internal SimpleExcelDocument()
        {
            sheetData = new SheetData();
        }

        #region Get Cell Reference
        public Cell GetCell(string fullAddress)
        {
            return sheetData.Descendants<Cell>().Where(c => c.CellReference == fullAddress).FirstOrDefault();
        }
        public Cell GetCell(uint rowId, uint columnId, bool autoCreate)
        {
            return GetCell(getColumnName(columnId), rowId, autoCreate);
        }
        public Cell GetCell(string columnName, uint rowId, bool autoCreate)
        {
            return getCell(sheetData, columnName, rowId, autoCreate);
        }
        #endregion

        #region Get Cell Contents
        // See: http://msdn.microsoft.com/en-us/library/ff921204.aspx
        // 
        #endregion


        #region Set Cell Contents
        public void SetValue(uint rowId, uint columnId, bool value)
        {
            Cell cell = GetCell(rowId, columnId, true);
            cell.DataType = CellValues.Boolean;
            cell.CellValue = new CellValue(BooleanValue.FromBoolean(value));
        }
        public void SetValue(uint rowId, uint columnId, double value)
        {
            Cell cell = GetCell(rowId, columnId, true);
            cell.DataType = CellValues.Number;
            cell.CellValue = new CellValue(DoubleValue.FromDouble(value));
        }
        public void SetValue(uint rowId, uint columnId, Int64 value)
        {
            Cell cell = GetCell(rowId, columnId, true);
            cell.DataType = CellValues.Number;
            cell.CellValue = new CellValue(IntegerValue.FromInt64(value));
        }
        public void SetValue(uint rowId, uint columnId, DateTime value)
        {
            Cell cell = GetCell(rowId, columnId, true);
            //cell.DataType = CellValues.Date;
            cell.CellValue = new CellValue(value.ToOADate().ToString());
            cell.StyleIndex = 1;
        }
        public void SetValue(uint rowId, uint columnId, string value)
        {
            Cell cell = GetCell(rowId, columnId, true);
            cell.InlineString = new InlineString(value.ToString());
            cell.DataType = CellValues.InlineString;
        }
        public void SetValue(uint rowId, uint columnId, object value)
        {             
            bool boolResult;
            Int64 intResult;
            DateTime dateResult;
            Double doubleResult;
            string stringResult = value.ToString();

            if (bool.TryParse(stringResult, out boolResult))
            {
                SetValue(rowId, columnId, boolResult);
            }
            else if (DateTime.TryParse(stringResult, out dateResult))
            {
                SetValue(rowId, columnId,dateResult);
            }
            else if (Int64.TryParse(stringResult, out intResult))
            {
                SetValue(rowId, columnId, intResult);
            }
            else if (Double.TryParse(stringResult, out doubleResult))
            {
                SetValue(rowId, columnId, doubleResult);
            }
            else
            {
                // Just assume that it is a plain string.
                SetValue(rowId, columnId, stringResult);
            }
        }
        #endregion

        public SheetData ExportAsSheetData()
        {
            return sheetData;
        }

        public void ExportAsXLSXStream(Stream outputStream)
        {
            // See: http://blogs.msdn.com/b/chrisquon/archive/2009/07/22/creating-an-excel-spreadsheet-from-scratch-using-openxml.aspx for some ideas...
            // See: http://stackoverflow.com/questions/1271520/opening-xlsx-in-office-2003

            using (SpreadsheetDocument package = SpreadsheetDocument.Create(outputStream, SpreadsheetDocumentType.Workbook))
            {
                // Setup the basics of a spreadsheet document.
                package.AddWorkbookPart();
                package.WorkbookPart.Workbook = new Workbook();
                WorksheetPart workSheetPart = package.WorkbookPart.AddNewPart<WorksheetPart>();
                workSheetPart.Worksheet = new Worksheet(sheetData);
                workSheetPart.Worksheet.Save();

                // create the worksheet to workbook relation
                package.WorkbookPart.Workbook.AppendChild(new Sheets());
                Sheet sheet = new Sheet { 
                    Id = package.WorkbookPart.GetIdOfPart(workSheetPart), 
                    SheetId = 1, 
                    Name = "Sheet 1" 
                };
                package.WorkbookPart.Workbook.GetFirstChild<Sheets>().AppendChild<Sheet>(sheet);
                package.WorkbookPart.Workbook.Save();
                package.Close();
            }
        }

        #region Internal Methods
        private static string getColumnName(uint columnId)
        {
            if (columnId < 1)
            {
                throw new Exception("The column # can't be less then 1.");
            }
            columnId--;
            if (columnId >= 0 && columnId < 26)
                return ((char)('A' + columnId)).ToString();
            else if (columnId > 25)
                return getColumnName(columnId / 26) + getColumnName(columnId % 26 + 1);
            else
                throw new Exception("Invalid Column #" + (columnId + 1).ToString());
        }

        // Given a worksheet, a column name, and a row index, 
        // gets the cell at the specified column 
        private static Cell getCell(SheetData worksheet,
                  string columnName, uint rowIndex, bool autoCreate)
        {
            Row row = getRow(worksheet, rowIndex, autoCreate);

            if (row == null)
                return null;

            Cell foundCell = row.Elements<Cell>().Where(c => string.Compare
                   (c.CellReference.Value, columnName +
                   rowIndex, true) == 0).FirstOrDefault();

            if (foundCell == null && autoCreate)
            {
                foundCell = new Cell();
                foundCell.CellReference = columnName;
                row.AppendChild(foundCell);
            }
            return foundCell;
        }


        // Given a worksheet and a row index, return the row.
        // See: http://msdn.microsoft.com/en-us/library/bb508943(v=office.12).aspx#Y2142
        private static Row getRow(SheetData worksheet, uint rowIndex, bool autoCreate)
        {
            if (rowIndex < 1)
            {
                throw new Exception("The row # can't be less then 1.");
            }

            Row foundRow = worksheet.Elements<Row>().Where(r => r.RowIndex == rowIndex).FirstOrDefault();

            if (foundRow == null && autoCreate)
            {
                foundRow = new Row();
                foundRow.RowIndex = rowIndex;
                worksheet.AppendChild(foundRow);
            }
            return foundRow;
        } 
        #endregion
        #region IDisposable Stuff
        private bool _disposed;
        //private bool _transactionComplete;

        /// <summary>
        /// This will dispose of any open resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);

            // Use SupressFinalize in case a subclass
            // of this type implements a finalizer.
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            // If you need thread safety, use a lock around these 
            // operations, as well as in your methods that use the resource.
            if (!_disposed)
            {
                if (disposing)
                {
                    //if (!_transactionComplete)
                    //    Commit();
                }

                // Indicate that the instance has been disposed.
                //_transaction = null;
                _disposed = true;
            }
        }
        #endregion
    }

Another BIG BIG vote for: https://github.com/closedxml/closedxml

After trying to build my own class from the bits and pieces spread around the net, including StackOverFlow, I found the above mentioned library and in a few moments had a fully functional Excel file.

I have pasted my attempt below for the edification of anyone that feels the urge to complete it. It is partially complete and has issues with the date and string cell creation.

Before you try to use this class, first download closedXML and try that first.

Consider yourself warned.

    /// <summary>
    /// This class allows for the easy creation of a simple Excel document who's sole purpose is to contain some export data.
    /// The document is created using OpenXML.
    /// </summary>
    internal class SimpleExcelDocument : IDisposable
    {
        SheetData sheetData;

        /// <summary>
        /// Constructor is nothing special because the work is done at export.
        /// </summary>
        internal SimpleExcelDocument()
        {
            sheetData = new SheetData();
        }

        #region Get Cell Reference
        public Cell GetCell(string fullAddress)
        {
            return sheetData.Descendants<Cell>().Where(c => c.CellReference == fullAddress).FirstOrDefault();
        }
        public Cell GetCell(uint rowId, uint columnId, bool autoCreate)
        {
            return GetCell(getColumnName(columnId), rowId, autoCreate);
        }
        public Cell GetCell(string columnName, uint rowId, bool autoCreate)
        {
            return getCell(sheetData, columnName, rowId, autoCreate);
        }
        #endregion

        #region Get Cell Contents
        // See: http://msdn.microsoft.com/en-us/library/ff921204.aspx
        // 
        #endregion


        #region Set Cell Contents
        public void SetValue(uint rowId, uint columnId, bool value)
        {
            Cell cell = GetCell(rowId, columnId, true);
            cell.DataType = CellValues.Boolean;
            cell.CellValue = new CellValue(BooleanValue.FromBoolean(value));
        }
        public void SetValue(uint rowId, uint columnId, double value)
        {
            Cell cell = GetCell(rowId, columnId, true);
            cell.DataType = CellValues.Number;
            cell.CellValue = new CellValue(DoubleValue.FromDouble(value));
        }
        public void SetValue(uint rowId, uint columnId, Int64 value)
        {
            Cell cell = GetCell(rowId, columnId, true);
            cell.DataType = CellValues.Number;
            cell.CellValue = new CellValue(IntegerValue.FromInt64(value));
        }
        public void SetValue(uint rowId, uint columnId, DateTime value)
        {
            Cell cell = GetCell(rowId, columnId, true);
            //cell.DataType = CellValues.Date;
            cell.CellValue = new CellValue(value.ToOADate().ToString());
            cell.StyleIndex = 1;
        }
        public void SetValue(uint rowId, uint columnId, string value)
        {
            Cell cell = GetCell(rowId, columnId, true);
            cell.InlineString = new InlineString(value.ToString());
            cell.DataType = CellValues.InlineString;
        }
        public void SetValue(uint rowId, uint columnId, object value)
        {             
            bool boolResult;
            Int64 intResult;
            DateTime dateResult;
            Double doubleResult;
            string stringResult = value.ToString();

            if (bool.TryParse(stringResult, out boolResult))
            {
                SetValue(rowId, columnId, boolResult);
            }
            else if (DateTime.TryParse(stringResult, out dateResult))
            {
                SetValue(rowId, columnId,dateResult);
            }
            else if (Int64.TryParse(stringResult, out intResult))
            {
                SetValue(rowId, columnId, intResult);
            }
            else if (Double.TryParse(stringResult, out doubleResult))
            {
                SetValue(rowId, columnId, doubleResult);
            }
            else
            {
                // Just assume that it is a plain string.
                SetValue(rowId, columnId, stringResult);
            }
        }
        #endregion

        public SheetData ExportAsSheetData()
        {
            return sheetData;
        }

        public void ExportAsXLSXStream(Stream outputStream)
        {
            // See: http://blogs.msdn.com/b/chrisquon/archive/2009/07/22/creating-an-excel-spreadsheet-from-scratch-using-openxml.aspx for some ideas...
            // See: http://stackoverflow.com/questions/1271520/opening-xlsx-in-office-2003

            using (SpreadsheetDocument package = SpreadsheetDocument.Create(outputStream, SpreadsheetDocumentType.Workbook))
            {
                // Setup the basics of a spreadsheet document.
                package.AddWorkbookPart();
                package.WorkbookPart.Workbook = new Workbook();
                WorksheetPart workSheetPart = package.WorkbookPart.AddNewPart<WorksheetPart>();
                workSheetPart.Worksheet = new Worksheet(sheetData);
                workSheetPart.Worksheet.Save();

                // create the worksheet to workbook relation
                package.WorkbookPart.Workbook.AppendChild(new Sheets());
                Sheet sheet = new Sheet { 
                    Id = package.WorkbookPart.GetIdOfPart(workSheetPart), 
                    SheetId = 1, 
                    Name = "Sheet 1" 
                };
                package.WorkbookPart.Workbook.GetFirstChild<Sheets>().AppendChild<Sheet>(sheet);
                package.WorkbookPart.Workbook.Save();
                package.Close();
            }
        }

        #region Internal Methods
        private static string getColumnName(uint columnId)
        {
            if (columnId < 1)
            {
                throw new Exception("The column # can't be less then 1.");
            }
            columnId--;
            if (columnId >= 0 && columnId < 26)
                return ((char)('A' + columnId)).ToString();
            else if (columnId > 25)
                return getColumnName(columnId / 26) + getColumnName(columnId % 26 + 1);
            else
                throw new Exception("Invalid Column #" + (columnId + 1).ToString());
        }

        // Given a worksheet, a column name, and a row index, 
        // gets the cell at the specified column 
        private static Cell getCell(SheetData worksheet,
                  string columnName, uint rowIndex, bool autoCreate)
        {
            Row row = getRow(worksheet, rowIndex, autoCreate);

            if (row == null)
                return null;

            Cell foundCell = row.Elements<Cell>().Where(c => string.Compare
                   (c.CellReference.Value, columnName +
                   rowIndex, true) == 0).FirstOrDefault();

            if (foundCell == null && autoCreate)
            {
                foundCell = new Cell();
                foundCell.CellReference = columnName;
                row.AppendChild(foundCell);
            }
            return foundCell;
        }


        // Given a worksheet and a row index, return the row.
        // See: http://msdn.microsoft.com/en-us/library/bb508943(v=office.12).aspx#Y2142
        private static Row getRow(SheetData worksheet, uint rowIndex, bool autoCreate)
        {
            if (rowIndex < 1)
            {
                throw new Exception("The row # can't be less then 1.");
            }

            Row foundRow = worksheet.Elements<Row>().Where(r => r.RowIndex == rowIndex).FirstOrDefault();

            if (foundRow == null && autoCreate)
            {
                foundRow = new Row();
                foundRow.RowIndex = rowIndex;
                worksheet.AppendChild(foundRow);
            }
            return foundRow;
        } 
        #endregion
        #region IDisposable Stuff
        private bool _disposed;
        //private bool _transactionComplete;

        /// <summary>
        /// This will dispose of any open resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);

            // Use SupressFinalize in case a subclass
            // of this type implements a finalizer.
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            // If you need thread safety, use a lock around these 
            // operations, as well as in your methods that use the resource.
            if (!_disposed)
            {
                if (disposing)
                {
                    //if (!_transactionComplete)
                    //    Commit();
                }

                // Indicate that the instance has been disposed.
                //_transaction = null;
                _disposed = true;
            }
        }
        #endregion
    }
怪我太投入 2024-11-14 23:48:15

在尝试了很多帖子之后,我发现 .ToOADate() 和 CellValues.Number 和 cell.StyleIndex = 4 都是需要的......加上!所有模板日期列必须格式化为默认日期样式,以便日期可作为日期进行过滤。如果没有这些,打开 Excel 文件时会出现错误或值显示为数字。

using DocumentFormat.OpenXml.Packaging;  
using DocumentFormat.OpenXml.Spreadsheet;  

//  IMPORTANT! All template date columns MUST be formatted to the default date style for the dates to be filterable as dates  
Cell cell = new Cell();  
dataMember = dataMember.ToOADate().ToString();  //OA Date needed to export number as Date  
cell.DataType = CellValues.Number;                
cell.CellValue = new CellValue(dataMember);  
cell.StyleIndex = 4;                            // Date format: M/d/yyyy  

After trying numerous posts, I discovered that .ToOADate() and CellValues.Number and cell.StyleIndex = 4 were all needed...PLUS! All template date columns MUST be formatted to the default date style for the dates to be FILTERABLE as dates. Without these a error appeared upon opening the Excel file or the values were displayed as a number.

using DocumentFormat.OpenXml.Packaging;  
using DocumentFormat.OpenXml.Spreadsheet;  

//  IMPORTANT! All template date columns MUST be formatted to the default date style for the dates to be filterable as dates  
Cell cell = new Cell();  
dataMember = dataMember.ToOADate().ToString();  //OA Date needed to export number as Date  
cell.DataType = CellValues.Number;                
cell.CellValue = new CellValue(dataMember);  
cell.StyleIndex = 4;                            // Date format: M/d/yyyy  
陌伤浅笑 2024-11-14 23:48:15

我相信您的问题出在 NumberFormatId 上。内置数字格式的编号为 0 - 163。自定义格式必须从 164 开始。

I believe your problem is on NumberFormatId. Built-in number formats are numbered 0 - 163. Custom formats must start at 164.

浅唱ヾ落雨殇 2024-11-14 23:48:15

以下是如何在单元格上应用自定义日期格式。
首先,我们必须在工作簿的样式表中查找或创建格式:

// get the stylesheet from the current sheet    
var stylesheet = spreadsheetDoc.WorkbookPart.WorkbookStylesPart.Stylesheet;
// cell formats are stored in the stylesheet's NumberingFormats
var numberingFormats = stylesheet.NumberingFormats;

// cell format string               
const string dateFormatCode = "dd/mm/yyyy";
// first check if we find an existing NumberingFormat with the desired formatcode
var dateFormat = numberingFormats.OfType<NumberingFormat>().FirstOrDefault(format => format.FormatCode == dateFormatCode);
// if not: create it
if (dateFormat == null)
{
    dateFormat = new NumberingFormat
                {
                    NumberFormatId = UInt32Value.FromUInt32(164),  // Built-in number formats are numbered 0 - 163. Custom formats must start at 164.
                    FormatCode = StringValue.FromString(dateFormatCode)
                };
numberingFormats.AppendChild(dateFormat);
// we have to increase the count attribute manually ?!?
numberingFormats.Count = Convert.ToUInt32(numberingFormats.Count());
// save the new NumberFormat in the stylesheet
stylesheet.Save();
}
// get the (1-based) index of the dateformat
var dateStyleIndex = numberingFormats.ToList().IndexOf(dateFormat) + 1;

然后,我们可以使用解析的样式索引将格式应用到单元格:

cell.StyleIndex = Convert.ToUInt32(dateStyleIndex);

Here is how to apply a custom date format on a cell.
First, we have to lookup or create the format in the Workbook's Stylesheet:

// get the stylesheet from the current sheet    
var stylesheet = spreadsheetDoc.WorkbookPart.WorkbookStylesPart.Stylesheet;
// cell formats are stored in the stylesheet's NumberingFormats
var numberingFormats = stylesheet.NumberingFormats;

// cell format string               
const string dateFormatCode = "dd/mm/yyyy";
// first check if we find an existing NumberingFormat with the desired formatcode
var dateFormat = numberingFormats.OfType<NumberingFormat>().FirstOrDefault(format => format.FormatCode == dateFormatCode);
// if not: create it
if (dateFormat == null)
{
    dateFormat = new NumberingFormat
                {
                    NumberFormatId = UInt32Value.FromUInt32(164),  // Built-in number formats are numbered 0 - 163. Custom formats must start at 164.
                    FormatCode = StringValue.FromString(dateFormatCode)
                };
numberingFormats.AppendChild(dateFormat);
// we have to increase the count attribute manually ?!?
numberingFormats.Count = Convert.ToUInt32(numberingFormats.Count());
// save the new NumberFormat in the stylesheet
stylesheet.Save();
}
// get the (1-based) index of the dateformat
var dateStyleIndex = numberingFormats.ToList().IndexOf(dateFormat) + 1;

Then, we can apply our format to a cell, using the resolved styleindex:

cell.StyleIndex = Convert.ToUInt32(dateStyleIndex);
剩一世无双 2024-11-14 23:48:15

您的答案可以在什么表示Office Open XML 单元格包含日期/时间值?

技巧在于单元格的 StyleIndex(s 属性)实际上是单元格样式列表(XF 元素)的索引,该列表位于样式部分你的电子表格。其中每一个都将指向 Samuel 提到的预定义数字格式 ID。如果我没记错的话,您要查找的数字格式 ID 是 14 或 15。

Your answer can be found at What indicates an Office Open XML Cell contains a Date/Time value?

The trick is that the StyleIndex (s-attribute) of the cell is literally an index into the list of cell styles (XF-elements) in the styles part of your spreadsheet. Each of those will point to the predefined number format ids that Samuel mentions. If I remember correctly the number format id you are looking for is either 14 or 15.

尘曦 2024-11-14 23:48:15

我遇到了同样的问题,最终编写了自己的导出到 Excel writer。代码是为了解决这个问题,但是使用整个导出器确实会更好。它速度很快,并且允许对单元格进行大量格式化。您可以在

https://openxmlexporttoexcel.codeplex.com/

查看它,希望它有所帮助。

I had the same issue and ended up writing my own export to Excel writer. The code is in there to solve this problem, but you would truly be better off just using the whole exporter. It is fast and allows for substantial formatting of the cells. You can review it at

https://openxmlexporttoexcel.codeplex.com/

I hope it helps.

思念满溢 2024-11-14 23:48:15

我希望以下链接对未来的访客有所帮助。

首先,获取标准文档

ECMA-376 第 4 版第 1 部分是最有帮助的文档。本文档中与此问题相关的部分是:

18.8.30

18.8.31(这个狗屎的语义)

18.8.45(excel 理解的样式的定义)

L.2.7.3.6(如何引用样式)

I hope the following links will be of help to future visitors.

First, Get the standards documentation.

ECMA-376 4th Edition Part 1 is the most helpful document. Sections in this document that relate to this question are:

18.8.30

18.8.31 (sematics of this shitty shit)

18.8.45 (definition of a style as understood by excel)

L.2.7.3.6 (How styles are referenced)

很酷又爱笑 2024-11-14 23:48:15

要了解为什么 CellValues.Date 数据类型不起作用(至少在所有 Excel 版本中似乎不起作用),请参阅:

使用 OpenXML 在 Excel 单元格中添加日期

有关完整、有效且解释良好的解决方案,请参阅:

OpenXML - 将日期写入 Excel 电子表格会导致内容不可读

For understanding why the CellValues.Date DataType does not work (at least not in all Excel versions it seems) please refer to this:

Adding a date in an Excel cell using OpenXML

For a complete, working, and well explained solution please refer to this:

OpenXML -Writing a date into Excel spreadsheet results in unreadable content

够运 2024-11-14 23:48:15

我遇到了同样的问题,涉及保存文档后格式化日期字段。解决方案是添加数字格式如下:

new NumberingFormat() { NumberFormatId = 164, FormatCode = StringValue.FromString($"[$-409]d\\-mmm\\-yyyy;@") }

并添加单元格,如下所示:

cell.CellValue = new CellValue(date.ToOADate().ToString());
cell.StyleIndex = 1; // your style index using numbering format above
cell.DataType = CellValues.Number;

I have encountered the same problem concerns formatting date field after save document. And the solution is to add number format as follows:

new NumberingFormat() { NumberFormatId = 164, FormatCode = StringValue.FromString($"[$-409]d\\-mmm\\-yyyy;@") }

and add cell like this:

cell.CellValue = new CellValue(date.ToOADate().ToString());
cell.StyleIndex = 1; // your style index using numbering format above
cell.DataType = CellValues.Number;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文