将数字格式化为日期涉及很多内容。
您需要从数字格式开始。识别与您想要的模式匹配的内置格式或创建自定义格式。内置格式在 ECMA-376, Second Edition, Part 1 - Fundamentals And Markup Language Reference section 18.8.30(样式参考和<numFmt>。如果您需要创建自定义格式,从 ID 164 开始,并将它们添加到您的 styles.xml 文件中的 <numFmts> 元素中。在 SDK 中可通过以下方式访问:
doc.WorkbookPart.WorkbookStylesPart.Stylesheet.NumberingFormats
接下来,您需要有一个引用日期格式的单元格格式。你总是需要一个单元格格式,没有内置的。单元格样式是指numFmtId 的数字格式,并在styles.xml 内<cellXfs> 内定义。这可以在 sdk 中访问:
doc.WorkbookPart.WorkbookStylesPart.Stylesheet.CellStyles
单元格样式本身没有 ID。它们由单元格样式列表中的零索引位置引用。因此,当您创建单元格时,请将它们的样式索引设置为您想要的日期样式。
对于值,您可以将它们存储为ISO 8601 格式,但 Excel 2010 仍使用日期序列格式来存储其日期。如果您使用的不是基于 1900 的日期序列,则需要在工作簿属性中指定它。
doc.WorkbookPart.Workbook.WorkbookProperties.DateCompatibility
有两种日期兼容性设置用于存储日期序列值,它们可以是基数 1900 或基数 1904。Excel 2010 使用 1900,而 1904 用于向后兼容旧版 Excel for Mac。
在以 1900 年为基础的日期序列中,数字是自 1899 年 12 月 31 日以来的天数,更复杂的是,即使 1900 年在技术上不是闰年,您也必须将 1900 年 2 月 29 日视为有效日期。
以下是我编写的将日期序列值转换为日期时间的方法。你需要反过来。
/// <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);
}