如何将日期插入到Open XML工作表中?

23

我正在使用Microsoft Open XML SDK 2,但是将日期插入单元格非常困难。通过设置Cell.DataType = CellValues.Number可以轻松地插入数字,但是当我使用相同的方法插入日期(Cell.DataType = CellValues.Date)时,Excel 2010(和2007)会崩溃。

我尝试将Cell.Text值设置为许多日期格式以及Excel的日期/数值格式,但都没有成功。我还尝试使用样式、删除type属性以及许多其他方法,但都无济于事。

有人能给我指示如何向工作表中插入日期的示例吗?

7个回答

36

我使用了Andrew J提供的代码,但是DataTypeCellValues.Date对我生成的xlsx文件损坏。

DataTypeCellValues.Number 对我来说工作正常 (不要忘记设置NumberFormatId):

cell.DataType = new EnumValue<CellValues>(CellValues.Number);

完整的代码:

DateTime valueDate = DateTime.Now;
string valueString = valueDate.ToOADate().ToString();
CellValue cellValue = new CellValue(valueString);

Cell cell = new Cell();
cell.DataType = new EnumValue<CellValues>(CellValues.Number);
cell.StyleIndex = yourStyle; //StyleIndex of CellFormat cfBaseDate -> See below
cell.Append(cellValue);

这个单元格在样式表中的CellFormat如下:

CellFormat cfBaseDate = new CellFormat() { 
 ApplyNumberFormat = true,
 NumberFormatId = 14, //14 is a localized short Date (d/m/yyyy) -> See list below
 //Some further styling parameters
}; 

如果您想以另一种方式格式化日期,这里是所有默认Excel NumberFormatId 的列表:

ID  格式码
0   常规
1   0
2   0.00
3   #,##0
4   #,##0.00
9   0%
10  0.00%
11  0.00E+00
12  # ?/?
13  # ??/??
14  d/m/yyyy
15  d-mmm-yy
16  d-mmm
17  mmm-yy
18  h:mm tt
19  h:mm:ss tt
20  H:mm
21  H:mm:ss
22  m/d/yyyy H:mm
37  #,##0 ;(#,##0)
38  #,##0 ;[红色](#,##0)
39  #,##0.00;(#,##0.00)
40  #,##0.00;[红色](#,##0.00)
45  mm:ss
46  [h]:mm:ss
47  mmss.0
48  ##0.0E+0
49  @

列表来源:https://github.com/ClosedXML/ClosedXML/wiki/NumberFormatId-Lookup-Table

我知道这个列表来自ClosedXML,但在OpenXML中也是相同的。


这对我非常有效,谢谢!正如你所说,被接受的解决方案对我并不起作用,因为Date类型实际上并不受支持。 - World Wide DBA

27

从头创建新的SpreadsheetDocument时,为了使Date格式化正常工作,必须创建最小的Stylesheet

关键是这几行:

new CellFormat
{
    NumberFormatId = 14,
    ApplyNumberFormat = true
})

完整的样式表类:

using (var spreadSheet = SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook))
{
    // Workbook
    var workbookPart = spreadSheet.AddWorkbookPart();
    workbookPart.Workbook =
        new Workbook(new Sheets(new Sheet { Name = "Sheet1", SheetId = (UInt32Value) 1U, Id = "rId1" }));

    // Add minimal Stylesheet
    var stylesPart = spreadSheet.WorkbookPart.AddNewPart<WorkbookStylesPart>();
    stylesPart.Stylesheet = new Stylesheet
    {
        Fonts = new Fonts(new Font()),
        Fills = new Fills(new Fill()),
        Borders = new Borders(new Border()),
        CellStyleFormats = new CellStyleFormats(new CellFormat()),
        CellFormats =
            new CellFormats(
                new CellFormat(),
                new CellFormat
                {
                    NumberFormatId = 14,
                    ApplyNumberFormat = true
                })
    };

    // Continue creating `WorksheetPart`...

在添加StyleSheet后,可以格式化DateTime
if (valueType == typeof(DateTime))
{
    DateTime date = (DateTime)value;
    cell.CellValue = new CellValue(date.ToOADate().ToString(CultureInfo.InvariantCulture));

    // "StyleIndex" is "1", because "NumberFormatId=14"
    // is in the 2nd item of `CellFormats` array.
    cell.StyleIndex = 1; 
}

请注意,StyleIndex值取决于CellFormats数组或Stylesheet对象中的CellFormat项目顺序。在此示例中,NumberFormatId = 14项目位于数组的第2个位置。


16
你需要使用函数 ToOADateDateTime 转换为 double,例如:

DateTime dtValue = DateTime.Now;
string strValue = dtValue.ToOADate().ToString(CultureInfo.InvariantCulture);

然后将其设置为CellValue

Cell cell;
cell.DataType = new EnumValue<CellValues>(CellValues.Date);
cell.CellValue = new CellValue(strValue);

记得使用DateTime格式化单元格,否则您将看到double值,而不是日期。


要注意1904标志 - 日期可以设置为从1-1-1900或1-1-1904(因为它计算闰年的方式存在错误)。 - David Thielen
5
很奇怪,这对我没有用。即使在 Excel 2010 上也不行。(2007 年的 CellValues.Date 应该不支持) - GaussZ
2
不要只调用ToString()并尝试替换“,”。请调用ToString(CultureInfo.InvariantCulture),以确保正确的格式。编译器和Resharper甚至有对此事的警告。 - Panagiotis Kanavos
2
不幸的是,这并不起作用 - 或许从答案发布时起有些变化了。Excel 365无法识别格式,您的电子表格已损坏。 - IamSierraCharlie

5
在OpenXml中,存储日期有两种方式。第一种是通过编写数字(使用ToOADate),并将DataType设置为Number。第二种是编写ISO 8601格式的日期,并将DataType设置为Date。请注意,默认DataTypeNumber,因此如果您选择第一种选项,则不必设置DataType

无论您选择哪种方法,都需要将样式设置为Excel显示两种方法相同。以下代码展示了使用Number格式(显式设置和未显式设置DataType)以及使用ISO 8601格式编写日期的示例。

using (SpreadsheetDocument document = SpreadsheetDocument.Create(filename, SpreadsheetDocumentType.Workbook))
{
    //fluff to generate the workbook etc
    WorkbookPart workbookPart = document.AddWorkbookPart();
    workbookPart.Workbook = new Workbook();

    var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
    worksheetPart.Worksheet = new Worksheet();

    Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());

    Sheet sheet = new Sheet() { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Sheet" };
    sheets.Append(sheet);

    workbookPart.Workbook.Save();

    var sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());

    //add the style
    Stylesheet styleSheet = new Stylesheet();

    CellFormat cf = new CellFormat();
    cf.NumberFormatId = 14;
    cf.ApplyNumberFormat = true;

    CellFormats cfs = new CellFormats();
    cfs.Append(cf);
    styleSheet.CellFormats = cfs;

    styleSheet.Borders = new Borders();
    styleSheet.Borders.Append(new Border());
    styleSheet.Fills = new Fills();
    styleSheet.Fills.Append(new Fill());
    styleSheet.Fonts = new Fonts();
    styleSheet.Fonts.Append(new Font());

    workbookPart.AddNewPart<WorkbookStylesPart>();
    workbookPart.WorkbookStylesPart.Stylesheet = styleSheet;

    CellStyles css = new CellStyles();
    CellStyle cs = new CellStyle();
    cs.FormatId = 0;
    cs.BuiltinId = 0;
    css.Append(cs);
    css.Count = UInt32Value.FromUInt32((uint)css.ChildElements.Count);
    styleSheet.Append(css);

    Row row = new Row();

    DateTime date = new DateTime(2017, 6, 24);

    /*** Date code here ***/
    //write an OADate with type of Number
    Cell cell1 = new Cell();
    cell1.CellReference = "A1";
    cell1.CellValue = new CellValue(date.ToOADate().ToString());
    cell1.DataType = new EnumValue<CellValues>(CellValues.Number);
    cell1.StyleIndex = 0;
    row.Append(cell1);

    //write an OADate with no type (defaults to Number)
    Cell cell2 = new Cell();
    cell2.CellReference = "B1";
    cell2.CellValue = new CellValue(date.ToOADate().ToString());
    cell1.StyleIndex = 0;
    row.Append(cell2);

    //write an ISO 8601 date with type of Date
    Cell cell3 = new Cell();
    cell3.CellReference = "C1";
    cell3.CellValue = new CellValue(date.ToString("yyyy-MM-dd"));
    cell3.DataType = new EnumValue<CellValues>(CellValues.Date);
    cell1.StyleIndex = 0;
    row.Append(cell3);

    sheetData.AppendChild(row);

    worksheetPart.Worksheet.Save();
}

0

使用共享字符串:

// assuming it's the first item in the shared string table
SharedStringItem sharedStringItem = new SharedStringItem();
Text text = new Text();
text.Text = DateTime.Today.ToString("MM/dd/yyyy hh:mm");
sharedStringTable1.Append(sharedStringItem);

然后在代码中:

// assuming it's the first item in the shared string table
var cell = new Cell {CellReference = "A1", DataType = CellValues.SharedString};
var cellValue = new CellValue("0");
cell.Append(cellValue);

0

以下方法适用于我们:

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

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


2
你如何查找StyleDate? - user236215

0

a) 获得与Excel 2007、Excel 2007 Viewer等的兼容性。 b) 将1900年1月1日之前的日期时间写为字符串。

DateTime dat = (DateTime)dr[dc.ColumnName];

//Not working with Excel 2007
//cell.DataType = CellValues.Date;
//cell.CellValue = new CellValue(dat.ToString("s"));

double diff = (dat - new DateTime(1899, 12, 30)).TotalSeconds / 86400.0;
if (diff > 1)
{
    cell.DataType = CellValues.Number;
    cell.CellValue = new CellValue(diff.ToString().Replace(",", "."));

    if (dat.TimeOfDay == new TimeSpan(0))
    {                                
        cell.StyleIndex = 2;   //Custom Style NumberFormatId = 14 ( d/m/yyyy)
    }
    else
    {
        cell.StyleIndex = 1;   //Custom Style NumberFormatId = 22 (m/d/yyyy H:mm)
    }
}
else
{
    cell.DataType = CellValues.String;
    cell.CellValue = new CellValue(dat.ToString());
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接