简体   繁体   English

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

[英]How to insert a date to an Open XML worksheet?

I'm using Microsoft Open XML SDK 2 and I'm having a really hard time inserting a date into a cell. 我正在使用Microsoft Open XML SDK 2,我很难在单元格中插入日期。 I can insert numbers without a problem by setting Cell.DataType = CellValues.Number , but when I do the same with a date ( Cell.DataType = CellValues.Date ) Excel 2010 crashes (2007 too). 我可以通过设置Cell.DataType = CellValues.Number来插入数字而没有问题,但是当我对日期( Cell.DataType = CellValues.Date )执行相同操作时,Excel 2010会崩溃(2007年也是如此)。

I tried setting the Cell.Text value to many date formats as well as Excel's date/numeric format to no avail. 我尝试将Cell.Text值设置为多种日期格式以及Excel的日期/数字格式无济于事。 I also tried to use styles, removing the type attribute, plus many other pizzas I threw at the wall… 我也尝试使用样式,删除type属性,以及我扔在墙上的许多其他比萨...

Can anyone point me to an example inserting a date to a worksheet? 有人能指出我在工作表中插入日期的例子吗?

I used the code provided by Andrew J, but the DataType CellValues.Date produced a corrupted xlsx-file for me. 我使用了Andrew J提供的代码,但DataType CellValues.Date为我生成了一个损坏的xlsx文件。

The DataType CellValues.Number worked fine for me (Don't forget to set NumberFormatId ) : DataType CellValues.Number对我来说很好(不要忘记设置NumberFormatId

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

My whole code: 我的整个代码:

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);

My CellFormat for this cell in the Stylesheet looks like: 样式表中此单元格的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
}; 

If you'd like to format your date another way, here is a list of all default Excel NumberFormatId 's 如果您想以另一种方式格式化日期,这里是所有默认Excel NumberFormatId的列表

ID  FORMAT CODE
0   General
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 ;[Red](#,##0)
39  #,##0.00;(#,##0.00)
40  #,##0.00;[Red](#,##0.00)
45  mm:ss
46  [h]:mm:ss
47  mmss.0
48  ##0.0E+0
49  @

Source of list: https://github.com/ClosedXML/ClosedXML/wiki/NumberFormatId-Lookup-Table 清单来源: https//github.com/ClosedXML/ClosedXML/wiki/NumberFormatId-Lookup-Table

I know this list is from ClosedXML, but it's the same in OpenXML. 我知道这个列表来自ClosedXML,但它在OpenXML中是相同的。

You have to convert DateTime to double using function ToOADate ie: 您必须使用函数ToOADateDateTime转换为double即:

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

then set it as CellValue 然后将其设置为CellValue

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

Remember to format cell using DateTime formatting, otherwise you will see double value, not date. 请记住使用DateTime格式化格式化单元格,否则您将看到double值,而不是日期。

When creating new SpreadsheetDocument from scratch, for Date formatting to work, minimal Stylesheet has to be created. 从头开始创建新的SpreadsheetDocument ,要使Date格式化起作用,必须创建最小的Stylesheet

Critical are those few lines: 关键是那几行:

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

Full Stylesheet class: 完整Stylesheet类:

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`...

After Stylesheet is added, DateTime can be formatted: 添加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; 
}

Note that StyleIndex value depends on the order of CellFormat items in the CellFormats array or the Stylesheet object. 请注意, StyleIndex值取决于CellFormats数组或Stylesheet对象中CellFormat项的顺序。 In this example NumberFormatId = 14 item on the 2nd item in the array. 在此示例中,数组中第二项的NumberFormatId = 14项。

There are 2 ways to store dates in OpenXml; 有两种方法可以在OpenXml中存储日期; by writing a number (using ToOADate ) and setting the DataType to Number or by writing an ISO 8601 formatted date and setting the DataType to Date . 通过编写一个数字(使用ToOADate )并将DataType设置为Number或写入ISO 8601格式化日期并将DataType设置为Date Note that the default DataType is Number so if you go with the first option you don't have to set the DataType . 请注意,默认DataTypeNumber因此如果您使用第一个选项,则不必设置DataType

Whichever method you choose, you'll need to set the style as Excel displays both methods identically. 无论选择哪种方法,都需要设置样式,因为Excel会以相同的方式显示两种方法。 The following code shows an example of writing a date using the Number format (with and without explicitly setting the DataType ) and using the ISO 8601 format. 以下代码显示了使用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();
}

Use Shared String: 使用共享字符串:

// 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);

Then later in code: 然后在代码中:

// 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);

The following worked for us: 以下为我们工作:

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

Set the DataType to CellValues.Number and then be sure to format the cell with the appropriate style index from the CellFormats. 将DataType设置为CellValues.Number,然后确保使用CellFormats中的相应样式索引格式化单元格。 In our case we build a stylesheet within the worksheet, and StyleDate is an index into the CellFormats in the stylesheet. 在我们的例子中,我们在工作表中构建样式表,StyleDate是样式表中CellFormats的索引。

a) Get compatibility with Excel 2007, Excel 2007 Viewer etc. b) DateTime before 1.1.1900 write as string. a)与Excel 2007,Excel 2007 Viewer等兼容.b)1.1.1900之前的DateTime以字符串形式写入。

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());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM