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

Ext*_*kun 16 .net c# openxml

我使用以下代码将日期时间添加到电子表格中的列:

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
    });
Run Code Online (Sandbox Code Playgroud)

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

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
    });
Run Code Online (Sandbox Code Playgroud)

如果我注释掉这一行,一切都很好.

我在StackOverFlow上提到了simiiar问题,但它们基本上和我一样有相同的代码

Dav*_*ams 24

像往常一样迟到了派对,但我必须发布一个答案,因为以前的所有人都是完全错误的,除了Oleh的失败投票答案,这很遗憾.

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

将日期01/01/2015添加到单元格A1中会产生以下结果:

<row r="1">
  <c r="A1" s="0">
    <v>42005</v>
  </c>
</row>
Run Code Online (Sandbox Code Playgroud)

请注意,type属性存在.然而,有一个样式属性引用以下样式:

<xf numFmtId="14" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1" />
Run Code Online (Sandbox Code Playgroud)

这是您必须添加的最基本的样式.

所以生成上面的代码:

  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);
Run Code Online (Sandbox Code Playgroud)

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

不幸的是,似乎将只是上面的样式是不是很够,如果你这样做实际上导致Excel崩溃.需要注意的是BorderId,FillId,FontId需要对应的样式表,这意味着你需要为他们提供的项目.GetStyleSheet()完整代码清单中的方法提供了Excel无错误工作所需的最小默认样式表.

  1. 并按如下方式添加单元格:
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
    }));
Run Code Online (Sandbox Code Playgroud)

注意: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
    }));
Run Code Online (Sandbox Code Playgroud)

结果:

<row>
  <c s="0" t="d">
    <v>2015-08-05T11:13:57</v>
  </c>
</row>
Run Code Online (Sandbox Code Playgroud)

完整的代码清单

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

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这个人太复杂了。我刚刚放弃并将日期值添加为字符串。 (3认同)

Mic*_*nis 6

尝试指示它是一种CellValues.String类型,而不是CellValues.Date类型.

使用

ToString()

代替

CellValues.Date

现在,在没有ToString()转换的情况下将其添加为日期是有意义的,并使用CellValues.StringDataType - 但CellValue()仅将字符串作为参数.[为什么,OpenXmlSDK,为什么 ??? 你是一个包装者.很好地包装好东西.让它们隐形,让我的生活更轻松.:::叹:::]

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

但我发现,虽然CellValues.DateCellValues.Date都得到预期(相同的)格式,只有CellValues.Date抛出抛出了载了"无法读取内容".

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

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


Yah*_*hia 5

尝试dt.ToOADate().ToString().Replace (",", ".")而不是dt.ToOADate().ToString()

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

编辑:

请将您的代码更改为:

dt.ToOADate().ToString(new CultureInfo("en-US"));
Run Code Online (Sandbox Code Playgroud)

  • 不起作用.我在工作表中看到一个浮点数.关于这个问题没有一个答案. (5认同)