2010-07-22 48 views
6

我无法找到这一个。C#打开Xml SDK 2.0电子表格设置单元日期时间格式

我的情况:

  • SDK 2.0
  • 没有电子表格模板
  • 下,在VS2010#4.0

我的问题:
在Excel文件我想建立一些数据存在采用DateTime格式。由于我不想只使用字符串(弦乐日期时间无法正确排序),我想将包含DateTime的单元格设置为我选择的格式,就像我在Excel中所做的那样。
据我的理解,我必须使用样式表来达到这一点。我一直浏览网络一段时间,找到一个对此问题有简单解释的人,但似乎很难找到。

我已经在mem中有一个电子表格,可以通过SheetData添加数据。 我唯一缺少的是单元格的格式/样式。

这是我迄今为止得到:

DocumentFormat.OpenXml.Packaging.SpreadsheetDocument doc = SpreadsheetDocument.Create("test.xlsx", SpreadsheetDocumentType.Workbook); 

WorkbookPart wbPart = doc.AddWorkbookPart(); 
wbPart.Workbook = new Workbook(); 

SheetData data = new SheetData(
      new Row(...etc)); 

WorksheetPart wsPart = wbPart.AddNewPart<WorksheetPart>(); 
wsPart.Worksheet = new Worksheet(data); 

Sheets sheets = doc.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets()); 

Sheet sheet = new Sheet() { Id = doc.WorkbookPart.GetIdOfPart(wsPart), SheetId = 1, Name = "TestSheet" }; 
sheets.Append(sheet); 

wbPart.Workbook.Save(); 

doc.Close(); 

在何处以及如何我可以添加简单的补充,如日期时间样式(例如,“DD-MM-YYYY”),也许更先进的造型以后?

我希望我是在那时我会继续寻找足够:) 具体...

THX!

+0

你有没有工作,这一点建议? – 2011-01-17 14:19:30

+0

您没有阅读过Office Open XML规范吗?它只有6,000页... :-)当然,我现在正在与类似的“小”问题进行斗争。 – 2011-01-18 22:52:30

+1

都能跟得上我从来没有,我们对此深感抱歉...... 我们决定使用第三方工具,使表:) – 2011-01-27 12:16:00

回答

3

作为日期格式化数字有很多。

您需要以数字格式开头。要么标识与您想要的模式匹配的内置格式,要么创建一个自定义格式。内置格式为ECMA-376,第二版,第1部分 - 基础和标记语言参考section 18.8.30(样式参考和<numFmt>。如果您需要创建自定义格式,请从ID 164开始并将它们添加到。

doc.WorkbookPart.WorkbookStylesPart.Stylesheet.NumberingFormats 

接下来,你需要有一个指向一个日期格式的单元格的格式你总是需要一个单元格的格式,没有内置:你styles.xml文件中<numFmts>元素这是SDK访问。单元格样式是指numFmtId的数字格式,在<cellXfs>的内部定义在styles.xml内,可以在sdk中作为:

doc.WorkbookPart.WorkbookStylesPart.Stylesheet.CellStyles 

单元格样式本身没有ID。它们由单元格样式列表中的零索引位置引用。因此,当您创建单元格时,请将其样式索引设置为您想要的日期样式。

对于该值,可以将它们存储为ISO 8601格式,但Excel 2010仍使用日期序列格式来存储其日期。如果您使用除基于1900的日期序列以外的其他任何内容,则需要在工作簿属性中指定它。

doc.WorkbookPart.Workbook.WorkbookProperties.DateCompatibility 

有用于存储日期序列值的两个日期的兼容性设置,也可以是基地1900或1904年基地1900就是Excel 2010中的用途和1904是与旧的Excel的Mac向后兼容性。

基于1900年的日期连续出版物中的数字是自1899年12月31日以来的日子,其中增加了一些复杂因素,您必须将1900年2月29日作为有效日期处理,尽管技术上1900年不是闰年。

下面是我写的,从日期序列值转换为DateTime的方法。你需要相反的。

/// <summary> 
/// Represents the formula used for converting date serial values stored within the workbook into DateTime instances. 
/// </summary> 
/// <remarks> 
/// Information on date serial conversion is available here: http://www.documentinteropinitiative.com/implnotes/ISO-IEC29500-2008/001.018.017.004.001.000.000.aspx 
/// </remarks> 
public enum XlsxDateCompatibility 
{ 
    /// <summary> 
    /// Standard dates are based on December 30, 1899 and are considered "Standard 1900" dates. 
    /// </summary> 
    StandardBase1900, 

    /// <summary> 
    /// Excel for Windows backwards compatible dates are based on December 31, 1899 are are considered "Backwards compatible 1900" dates. 
    /// </summary> 
    BackwardsCompatibleBase1900, 

    /// <summary> 
    /// Excel for Macintos backwards compatible dates are based on January 1, 1904 and are considered "1904" dates. 
    /// </summary> 
    BackwardsCompatibleBase1904 
} 

    private static readonly IDictionary<XlsxDateCompatibility, DateTime> _dateSerialBaseDates 
     = new Dictionary<XlsxDateCompatibility, DateTime> 
      { 
       {XlsxDateCompatibility.StandardBase1900, new DateTime(1899, 12, 30)}, 
       {XlsxDateCompatibility.BackwardsCompatibleBase1900, new DateTime(1899, 12, 31)}, 
       {XlsxDateCompatibility.BackwardsCompatibleBase1904, new DateTime(1904, 1, 1)} 
      }; 

    public static DateTime DateSerialToDateTime(double dateSerial, XlsxDateCompatibility dateCompatibility) 
    { 

     // special case for dateCompaitility 1900, Excel thinks 1900 is a leap year 
     // http://support.microsoft.com/kb/214019 
     if (dateCompatibility == XlsxDateCompatibility.BackwardsCompatibleBase1900 && dateSerial >= 61.0) 
     { 
      dateSerial -= 1; 
     } 

     DateTime baseDate;   
     if (!_dateSerialBaseDates.TryGetValue(dateCompatibility, out baseDate)) 
     { 
      baseDate = _dateSerialBaseDates[XlsxDateCompatibility.StandardBase1900]; 
     } 
     return baseDate.AddDays(dateSerial); 
    }