diff --git a/ClosedXML/Excel/CalcEngine/Functions/DateAndTime.cs b/ClosedXML/Excel/CalcEngine/Functions/DateAndTime.cs index 028d5c7..18c2c9d 100644 --- a/ClosedXML/Excel/CalcEngine/Functions/DateAndTime.cs +++ b/ClosedXML/Excel/CalcEngine/Functions/DateAndTime.cs @@ -91,7 +91,26 @@ var month = (int)p[1]; var day = (int)p[2]; - return (int)Math.Floor(new DateTime(year, month, day).ToOADate()); + // Excel allows months and days outside the normal range, and adjusts the date accordingly + if (month > 12 || month < 1) + { + year += (int)Math.Floor((double)(month - 1d) / 12.0); + month -= (int)Math.Floor((double)(month - 1d) / 12.0) * 12; + } + + int daysAdjustment = 0; + if (day > DateTime.DaysInMonth(year, month)) + { + daysAdjustment = day - DateTime.DaysInMonth(year, month); + day = DateTime.DaysInMonth(year, month); + } + else if (day < 1) + { + daysAdjustment = day - 1; + day = 1; + } + + return (int)Math.Floor(new DateTime(year, month, day).AddDays(daysAdjustment).ToOADate()); } private static object Datevalue(List p) diff --git a/ClosedXML_Tests/Excel/CalcEngine/DateAndTimeTests.cs b/ClosedXML_Tests/Excel/CalcEngine/DateAndTimeTests.cs index e6ed681..1d4c5d4 100644 --- a/ClosedXML_Tests/Excel/CalcEngine/DateAndTimeTests.cs +++ b/ClosedXML_Tests/Excel/CalcEngine/DateAndTimeTests.cs @@ -21,8 +21,25 @@ [Test] public void Date() { - Object actual = XLWorkbook.EvaluateExpr("Date(2008, 1, 1)"); + Object actual; + + actual = XLWorkbook.EvaluateExpr("Date(2008, 1, 1)"); Assert.AreEqual(39448, actual); + + actual = XLWorkbook.EvaluateExpr("Date(2008, 15, 1)"); + Assert.AreEqual(39873, actual); + + actual = XLWorkbook.EvaluateExpr("Date(2008, -50, 1)"); + Assert.AreEqual(37895, actual); + + actual = XLWorkbook.EvaluateExpr("Date(2008, 5, 63)"); + Assert.AreEqual(39631, actual); + + actual = XLWorkbook.EvaluateExpr("Date(2008, 13, 63)"); + Assert.AreEqual(39876, actual); + + actual = XLWorkbook.EvaluateExpr("Date(2008, 15, -120)"); + Assert.AreEqual(39752, actual); } [Test]