Excel 中 1 代表 1900-1-1,2 代表 1900-1-2,3 代表 1900-1-3……
所以通过 NPOI 取出日期后,实际取出的是数字,要进行转换,怎么转换呢?
var d = DecimalValue; int i = (int)d; // 整数部分。 var m = Math.Abs(d - (int)d); // 小数部分。0.5 表示 12 点、0.75 表示 18 点。 // 1 对应 1900-1-1。 // 60 对应 1900-2-29,错误日期,因为 1900 年并不是闰年,这是 Excel 的 BUG。 // 61 对应 1900-3-1,AddDays 减 2,因为有 1900-2-29 这个干扰。 // 86400 = 3600 * 24,小数部分对应的时间。 if (i >= 61) { // 注意 AddDays 减 2,因为有 1900-2-29 这个干扰。 return new DateTime(1900, 1, 1).AddDays(i - 2).AddSeconds((double)(86400 * m)); } else if (i >= 60) { throw new Exception("错误日期:1900-2-29"); } else if (i >= 1) { // 注意 AddDays 减 1。 return new DateTime(1900, 1, 1).AddDays(i - 1).AddSeconds((double)(86400 * m)); } else if (i >= 0) { // Excel 认为存在 1900-1-0 这一天。 throw new Exception("错误日期:1900-1-0"); } else { // Excel 都不认这个日期了。 throw new Exception("错误日期"); }
上面代码,为什么要 - 1,大家都知道,因为 1 代表 1900-1-1,而我们的初始值就是 1900-1-1,不需要再多加 1。
为什么要 - 2 呢?这是由于 Excel 中误认为 1900 年是闰年了,多了一个 1900-2-29,而实际上 1900 年是平年,没有 29 号。请参见:Excel 日期与数字对应关系的 BUG。
那是不是 Excel 误认为 2100 年也是闰年呢?还好,这个没错,Excel 没有把 2100 年误认为是闰年。