在Excel电子表格中写入日期会导致无法读取的内容

本文关键字:读取 电子表格 Excel 日期 | 更新日期: 2023-09-27 18:06:04

我使用以下代码将DateTime添加到电子表格中的一列:

var dt = DateTime.Now;
r.AppendChild<Cell>(new Cell()
    { 
        CellValue = new CellValue(dt.ToOADate().ToString()),
        DataType = new EnumValue<CellValues>(CellValues.Date), 
        StyleIndex = 1,
        CellReference = header[6] + index
    });

当我尝试在Excel 2010中打开文件时,我得到错误

Excel发现file.xlsx中有不可读的内容

如果我注释掉这行就没问题了。

我在StackOverflow上提到过类似的问题,但它们基本上和我一样有相同的代码。

在Excel电子表格中写入日期会导致无法读取的内容

像往常一样迟到了,但我必须发布一个答案,因为之前的所有答案都是完全错误的,除了Oleh的被投票的答案是不完整的。

由于这个问题与Excel有关,最简单的方法是创建一个Excel电子表格,其中包含您想要的数据和样式,然后将其作为部分打开并查看原始XML。

在单元格A1中添加日期01/01/2015,结果如下:

<row r="1">
  <c r="A1" s="0">
    <v>42005</v>
  </c>
</row>
注意type属性在这里是而不是。然而,一个样式属性,引用如下样式:
<xf numFmtId="14" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1" />

这是你必须添加的最基本的样式。

生成以上代码:

  1. 你需要创建一个样式如下:
var CellFormats = new CellFormats();
CellFormats.Append(new CellFormat()
{
    BorderId = 0,
    FillId = 0,
    FontId = 0,
    NumberFormatId = 14,
    FormatId = 0,
    ApplyNumberFormat = true
});
CellFormats.Count = (uint)CellFormats.ChildElements.Count;
var StyleSheet = new Stylesheet();
StyleSheet.Append(CellFormats);

NumberFormatId = 14指的是内置格式mm-dd-yy,这里是一些其他格式的列表。

不幸的是,似乎添加只是上面的风格是不够的,如果你这样做实际上会导致Excel崩溃。注意,BorderIdFillIdFontId需要对应于样式表中的一个项目,这意味着您需要提供它们。完整代码清单中的GetStyleSheet()方法提供了Excel正常工作所需的最小默认样式表。

  • 并添加如下单元格:
  • SheetData.AppendChild(new Row(
        new Cell() 
        { 
            // CellValue is set to OADate because that's what Excel expects.
            CellValue = new CellValue(date.ToOADate().ToString(CultureInfo.InvariantCulture)), 
            // Style index set to style (0 based).
            StyleIndex = 0
        }));
    

    注意:Office 2010和2013 可以处理日期不同,但默认情况下似乎没有。

    他们支持ISO 8601格式的日期,即yyyy-MM-ddTHH:mm:ss,正好这也是标准格式可排序("s"),所以你可以这样做:

    SheetData.AppendChild(new Row(
        new Cell() 
        { 
            CellValue = new CellValue(date.ToString("s")), 
            // This time we do add the DataType attribute but ONLY for Office 2010+.
            DataType = CellValues.Date
            StyleIndex = 1
        }));
    
    结果:

    <row>
      <c s="0" t="d">
        <v>2015-08-05T11:13:57</v>
      </c>
    </row>
    

    完整代码清单

    下面是添加具有日期格式的单元格所需的最小代码示例。

    private static void TestExcel()
    {
        using (var Spreadsheet = SpreadsheetDocument.Create("C:''Example.xlsx", SpreadsheetDocumentType.Workbook))
        {
            // Create workbook.
            var WorkbookPart = Spreadsheet.AddWorkbookPart();
            var Workbook = WorkbookPart.Workbook = new Workbook();
            // Add Stylesheet.
            var WorkbookStylesPart = WorkbookPart.AddNewPart<WorkbookStylesPart>();
            WorkbookStylesPart.Stylesheet = GetStylesheet();
            WorkbookStylesPart.Stylesheet.Save();
            // Create worksheet.
            var WorksheetPart = Spreadsheet.WorkbookPart.AddNewPart<WorksheetPart>();
            var Worksheet = WorksheetPart.Worksheet = new Worksheet();
            // Add data to worksheet.
            var SheetData = Worksheet.AppendChild(new SheetData());
            SheetData.AppendChild(new Row(
                new Cell() { CellValue = new CellValue(DateTime.Today.ToOADate().ToString(CultureInfo.InvariantCulture)), StyleIndex = 1 },
                // Only works for Office 2010+.
                new Cell() { CellValue = new CellValue(DateTime.Today.ToString("s")), DataType = CellValues.Date, StyleIndex = 1 }));
            // Link worksheet to workbook.
            var Sheets = Workbook.AppendChild(new Sheets());
            Sheets.AppendChild(new Sheet()
            {
                Id = WorkbookPart.GetIdOfPart(WorksheetPart),
                SheetId = (uint)(Sheets.Count() + 1),
                Name = "Example"
            });
            Workbook.Save();
        }
    }
    private static Stylesheet GetStylesheet()
    {
        var StyleSheet = new Stylesheet();
         // Create "fonts" node.
        var Fonts = new Fonts();
        Fonts.Append(new Font()
        {
            FontName = new FontName() { Val = "Calibri" },
            FontSize = new FontSize() { Val = 11 },
            FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 },
        });
        Fonts.Count = (uint)Fonts.ChildElements.Count;
        // Create "fills" node.
        var Fills = new Fills();
        Fills.Append(new Fill()
        {
            PatternFill = new PatternFill() { PatternType = PatternValues.None }
            });
            Fills.Append(new Fill()
            {
                PatternFill = new PatternFill() { PatternType = PatternValues.Gray125 }
            });
        Fills.Count = (uint)Fills.ChildElements.Count;
        // Create "borders" node.
        var Borders = new Borders();
        Borders.Append(new Border()
        {
            LeftBorder = new LeftBorder(),
            RightBorder = new RightBorder(),
            TopBorder = new TopBorder(),
            BottomBorder = new BottomBorder(),
            DiagonalBorder = new DiagonalBorder()
        });
        Borders.Count = (uint)Borders.ChildElements.Count;
        // Create "cellStyleXfs" node.
        var CellStyleFormats = new CellStyleFormats();
        CellStyleFormats.Append(new CellFormat()
        {
            NumberFormatId = 0,
            FontId = 0,
            FillId = 0,
            BorderId = 0
        });
        CellStyleFormats.Count = (uint)CellStyleFormats.ChildElements.Count;
        // Create "cellXfs" node.
        var CellFormats = new CellFormats();
        // A default style that works for everything but DateTime
        CellFormats.Append(new CellFormat()
        {
            BorderId = 0,
            FillId = 0,
            FontId = 0,
            NumberFormatId = 0,
            FormatId = 0,
            ApplyNumberFormat = true
        });
       // A style that works for DateTime (just the date)
       CellFormats.Append(new CellFormat()
        {
            BorderId = 0,
            FillId = 0,
            FontId = 0,
            NumberFormatId = 14, // or 22 to include the time
            FormatId = 0,
            ApplyNumberFormat = true
        });
        CellFormats.Count = (uint)CellFormats.ChildElements.Count;
        // Create "cellStyles" node.
        var CellStyles = new CellStyles();
        CellStyles.Append(new CellStyle()
        {
            Name = "Normal",
            FormatId = 0,
            BuiltinId = 0
        });
        CellStyles.Count = (uint)CellStyles.ChildElements.Count;
        // Append all nodes in order.
        StyleSheet.Append(Fonts);
        StyleSheet.Append(Fills);
        StyleSheet.Append(Borders);
        StyleSheet.Append(CellStyleFormats);
        StyleSheet.Append(CellFormats);
        StyleSheet.Append(CellStyles);
        return StyleSheet;
    }
    

    试着说明它是CellValues.String类型,而不是CellValues.Date类型。

    使用

    DataType = new EnumValue<CellValues>(CellValues.String)   // good
    
    不是

    DataType = new EnumValue<CellValues>(CellValues.Date)     // bad
    

    现在,将其添加为日期是有意义的,没有ToString()转换,并使用CellValues.Date DataType——但是CellValue()只接受字符串作为参数。

    [为什么,OpenXmlSDK, 为什么??你是个包装纸。把东西包装好。让他们隐形,让我的生活更轻松。:::叹息:::]

    另外,如果目标单元格希望格式化一个日期,我们应该指出它是一个日期。

    但是我发现,虽然CellValues.StringCellValues.Date都按预期格式化(相同),但只有CellValues.Date在加载时抛出"不可读内容"。

    我对dt.ToOADate().ToString(new CultureInfo("en-US"));方法的任何变化都完全没有运气——我最终得到一个五位数的数字,当它应该是一个格式化的日期时,它在电子表格中显示为五位数。

    我在添加字符串值时收到相同的错误消息,但使用CellValues.Number DataType。

    尝试用dt.ToOADate().ToString().Replace (",", ".")代替dt.ToOADate().ToString()

    有关一些工作代码示例,请参阅http://www.codeproject.com/KB/office/ExcelOpenXMLSDK.aspx

    编辑:

    请把你的代码改成:

    dt.ToOADate().ToString(new CultureInfo("en-US"));
    

    作为一个例子,您可以创建自己的excel文件与日期列。然后,如果您使用open XML SDK中的生产力工具打开它,您会发现没有为具有日期值的单元格指定DataType。这意味着在创建日期单元格时应该省略DataType。在这种情况下,还需要将dt.ToOADate().ToString()作为单元格值传递。

    以下代码可用于在电子表格中设置DateTime值:

    Cell cell = GetRequiredCell(); // It returns the required Cell
    DateTime dtValue = new DateTime(2012, 12, 8);
    string strValue = dtValue.ToOADate().ToString().Replace(",", ".");
    // decimal separator change it to "."
    cell.DataType = new EnumValue<CellValues>(CellValues.Number);
    cell.CellValue = new CellValue(strValue);
    cell.StyleIndex = 1; 
    
    private Cell CreateCellWithValue(DateTime columnValue, uint? styleIndex, string cellReference)
    {
        Cell c = new Cell();
        c.DataType = CellValues.Number;
        c.CellValue = new CellValue(columnValue.ToOADate().ToString(new CultureInfo("en-US")));
        c.CellReference = cellReference;
        c.StyleIndex = styleIndex;
        return c;
    }
    

    我们使用了以下方法:

    c.CellValue = new CellValue(datetimeValue).ToOADate().ToString());
    c.DataType = CellValues.Number;
    c.StyleIndex = StyleDate;
    

    DataType设置为CellValues.Number,然后确保使用CellFormats的适当样式索引格式化单元格。在本例中,我们在工作表中构建一个样式表,StyleDate是样式表中CellFormats的索引。