diff --git a/main/HSSF/UserModel/HSSFCell.cs b/main/HSSF/UserModel/HSSFCell.cs index 2a3eaea87..3fbf909a6 100644 --- a/main/HSSF/UserModel/HSSFCell.cs +++ b/main/HSSF/UserModel/HSSFCell.cs @@ -850,44 +850,53 @@ private void CheckFormulaCachedValueType(CellType expectedTypeCode, FormulaRecor /// /// Get the value of the cell as a date. For strings we throw an exception. - /// For blank cells we return a null. + /// For non-Numeric cells including blank cell we return a null. /// /// The date cell value. - public DateTime DateCellValue + public DateTime? DateCellValue { get { - if (cellType == CellType.Blank) + if (CellType != CellType.Numeric && CellType != CellType.Formula) { - return DateTime.MaxValue; + return null; } - if (cellType == CellType.String) - { - throw new InvalidDataException( - "You cannot get a date value from a String based cell"); - } - if (cellType == CellType.Boolean) - { - throw new InvalidDataException( - "You cannot get a date value from a bool cell"); - } - if (cellType == CellType.Error) + double value = this.NumericCellValue; + return DateUtil.GetJavaDate(value, book.IsDate1904()); + } + } +#if NET6_0_OR_GREATER + public DateOnly? DateOnlyCellValue + { + get{ + if (CellType != CellType.Numeric && CellType != CellType.Formula) { - throw new InvalidDataException( - "You cannot get a date value from an error cell"); + return null; } double value = this.NumericCellValue; if (book.IsDate1904()) { - return DateUtil.GetJavaDate(value, true); + return DateOnly.FromDateTime(DateUtil.GetJavaDate(value, true)); } else { - return DateUtil.GetJavaDate(value, false); + return DateOnly.FromDateTime(DateUtil.GetJavaDate(value, false)); + } + } + } + public TimeOnly? TimeOnlyCellValue + { + get{ + if (CellType != CellType.Numeric && CellType != CellType.Formula) + { + return null; } + double value = NumericCellValue; + bool date1904 = Sheet.Workbook.IsDate1904(); + return TimeOnly.FromDateTime(DateUtil.GetJavaDate(value, date1904)); } } - +#endif /// /// Get the value of the cell as a string - for numeric cells we throw an exception. /// For blank cells we return an empty string. diff --git a/main/SS/Format/CellFormat.cs b/main/SS/Format/CellFormat.cs index f0479a9d2..d6672a583 100644 --- a/main/SS/Format/CellFormat.cs +++ b/main/SS/Format/CellFormat.cs @@ -292,7 +292,7 @@ public CellFormatResult Apply(ICell c) { if (DateUtil.IsValidExcelDate(value)) { - return Apply(c.DateCellValue, value); + return Apply((DateTime)c.DateCellValue, value); } else { diff --git a/main/SS/UserModel/Cell.cs b/main/SS/UserModel/Cell.cs index 4a3db1654..f20ba7bcf 100644 --- a/main/SS/UserModel/Cell.cs +++ b/main/SS/UserModel/Cell.cs @@ -190,12 +190,21 @@ CellType CellType double NumericCellValue { get; } /// - /// Get the value of the cell as a date. + /// Get the value of the cell as a date. For non-Numeric cells including blank cell we return a null. /// /// if the cell type returned by GetCellType() is CELL_TYPE_STRING /// if the cell value isn't a parsable double - DateTime DateCellValue { get; } - + DateTime? DateCellValue { get; } +#if NET6_0_OR_GREATER + /// + /// Get DateOnly-type cell value + /// + DateOnly? DateOnlyCellValue { get; } + /// + /// Get TimeOnly-type cell value + /// + TimeOnly? TimeOnlyCellValue { get; } +#endif /// /// Get the value of the cell RichTextString /// diff --git a/main/SS/UserModel/DataFormatter.cs b/main/SS/UserModel/DataFormatter.cs index b9c692635..8a2b9102d 100644 --- a/main/SS/UserModel/DataFormatter.cs +++ b/main/SS/UserModel/DataFormatter.cs @@ -842,8 +842,10 @@ private String GetFormattedDateString(ICell cell) cell.NumericCellValue ); } - DateTime d = cell.DateCellValue; - return PerformDateFormatting(d, dateFormat); + var d = cell.DateCellValue; + if (d == null) + return ""; + return PerformDateFormatting((DateTime)d, dateFormat); } /** diff --git a/ooxml/XSSF/Streaming/SXSSFCell.cs b/ooxml/XSSF/Streaming/SXSSFCell.cs index e26f2849a..6ad4a5a95 100644 --- a/ooxml/XSSF/Streaming/SXSSFCell.cs +++ b/ooxml/XSSF/Streaming/SXSSFCell.cs @@ -15,6 +15,7 @@ the License. You may obtain a copy of the License at limitations under the License. ==================================================================== */ using System; +using System.IO; using NPOI.SS; using NPOI.SS.Formula.Eval; using NPOI.SS.UserModel; @@ -196,23 +197,51 @@ public int ColumnIndex return _row.GetCellIndex(this); } } - - public DateTime DateCellValue + /// + /// Get DateTime-type cell value + /// + public DateTime? DateCellValue { get { - CellType cellType = _value.GetType(); - if (cellType == CellType.Blank) + if (CellType != CellType.Numeric && CellType != CellType.Formula) { - return new DateTime(); + return null; } - double value = NumericCellValue; bool date1904 = Sheet.Workbook.IsDate1904(); - return DateUtil.GetJavaDate(value, date1904); + return DateUtil.GetJavaDate(value,date1904); } } - +#if NET6_0_OR_GREATER + /// + /// Get DateOnly-type cell value + /// + public DateOnly? DateOnlyCellValue + { + get{ + if (CellType != CellType.Numeric && CellType != CellType.Formula) + { + return null; + } + double value = NumericCellValue; + bool date1904 = Sheet.Workbook.IsDate1904(); + return DateOnly.FromDateTime(DateUtil.GetJavaDate(value, date1904)); + } + } + public TimeOnly? TimeOnlyCellValue + { + get{ + if (CellType != CellType.Numeric && CellType != CellType.Formula) + { + return null; + } + double value = NumericCellValue; + bool date1904 = Sheet.Workbook.IsDate1904(); + return TimeOnly.FromDateTime(DateUtil.GetJavaDate(value, date1904)); + } + } +#endif public byte ErrorCellValue { get diff --git a/ooxml/XSSF/UserModel/XSSFCell.cs b/ooxml/XSSF/UserModel/XSSFCell.cs index 803a9ebff..43686ad77 100644 --- a/ooxml/XSSF/UserModel/XSSFCell.cs +++ b/ooxml/XSSF/UserModel/XSSFCell.cs @@ -26,6 +26,8 @@ limitations under the License. using NPOI.Util; using NPOI.SS.Formula.Eval; using System.Globalization; +using System.IO; + namespace NPOI.XSSF.UserModel { @@ -827,13 +829,13 @@ private CellType GetBaseCellType(bool blankCells) /// /// Get the value of the cell as a date. /// - public DateTime DateCellValue + public DateTime? DateCellValue { get { - if (CellType == CellType.Blank) + if (CellType != CellType.Numeric && CellType != CellType.Formula) { - return DateTime.MinValue; + return null; } double value = NumericCellValue; @@ -841,6 +843,33 @@ public DateTime DateCellValue return DateUtil.GetJavaDate(value, date1904); } } +#if NET6_0_OR_GREATER + public DateOnly? DateOnlyCellValue + { + get{ + if (CellType != CellType.Numeric && CellType != CellType.Formula) + { + return null; + } + double value = NumericCellValue; + bool date1904 = Sheet.Workbook.IsDate1904(); + return DateOnly.FromDateTime(DateUtil.GetJavaDate(value, date1904)); + } + } + + public TimeOnly? TimeOnlyCellValue + { + get{ + if (CellType != CellType.Numeric && CellType != CellType.Formula) + { + return null; + } + double value = NumericCellValue; + bool date1904 = Sheet.Workbook.IsDate1904(); + return TimeOnly.FromDateTime(DateUtil.GetJavaDate(value, date1904)); + } + } +#endif public void SetCellValue(DateTime? value) { if (value == null) diff --git a/testcases/main/HSSF/UserModel/TestHSSFCell.cs b/testcases/main/HSSF/UserModel/TestHSSFCell.cs index 5ffe0f5b4..53b5eabfa 100644 --- a/testcases/main/HSSF/UserModel/TestHSSFCell.cs +++ b/testcases/main/HSSF/UserModel/TestHSSFCell.cs @@ -186,7 +186,7 @@ private static void SetCell(HSSFWorkbook workbook, int rowIdx, int colIdx, DateT cell.SetCellValue(date); } - private static DateTime ReadCell(HSSFWorkbook workbook, int rowIdx, int colIdx) + private static DateTime? ReadCell(HSSFWorkbook workbook, int rowIdx, int colIdx) { NPOI.SS.UserModel.ISheet sheet = workbook.GetSheetAt(0); IRow row = sheet.GetRow(rowIdx); @@ -485,7 +485,7 @@ public void TestCellType() HSSFCell cell = row.CreateCell(0) as HSSFCell; cell.SetCellType(CellType.Blank); - Assert.AreEqual("9999-12-31 23:59:59.999", cell.DateCellValue.ToString("yyyy-MM-dd HH:mm:ss.fff")); + Assert.IsNull(cell.DateCellValue); Assert.IsFalse(cell.BooleanCellValue); Assert.AreEqual("", cell.ToString()); @@ -520,6 +520,25 @@ public void TestCellType() cell.SetCellValue((IRichTextString)null); wb.Close(); } + + [Test] + public void TestGetDateTimeCellValue() + { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.CreateSheet() as HSSFSheet; + HSSFRow row = sheet.CreateRow(0) as HSSFRow; + HSSFCell cell = row.CreateCell(0) as HSSFCell; + cell.SetCellValue(new DateTime(2022, 5, 10, 13, 20, 50)); + Assert.IsNotNull(cell.DateCellValue); + Assert.AreEqual(new DateTime(2022, 5, 10, 13, 20, 50), cell.DateCellValue); +#if NET6_0_OR_GREATER + Assert.AreEqual(new DateOnly(2022, 5, 10), cell.DateOnlyCellValue); + Assert.AreEqual(new TimeOnly(13, 20, 50), cell.TimeOnlyCellValue); +#endif + HSSFCell cell2 = row.CreateCell(1) as HSSFCell; + cell2.SetCellValue("test"); + Assert.IsNull(cell2.DateCellValue); + } } } \ No newline at end of file diff --git a/testcases/main/HSSF/UserModel/TestHSSFDateUtil.cs b/testcases/main/HSSF/UserModel/TestHSSFDateUtil.cs index f17393232..6fc72a6f2 100644 --- a/testcases/main/HSSF/UserModel/TestHSSFDateUtil.cs +++ b/testcases/main/HSSF/UserModel/TestHSSFDateUtil.cs @@ -549,7 +549,7 @@ public void TestBug19172() cell.SetCellValue(valueToTest); - DateTime returnedValue = cell.DateCellValue; + DateTime returnedValue = (DateTime)cell.DateCellValue; Assert.AreEqual(valueToTest.TimeOfDay, returnedValue.TimeOfDay); } diff --git a/testcases/main/SS/UserModel/BaseTestCell.cs b/testcases/main/SS/UserModel/BaseTestCell.cs index 206c43787..dc5b7eb03 100644 --- a/testcases/main/SS/UserModel/BaseTestCell.cs +++ b/testcases/main/SS/UserModel/BaseTestCell.cs @@ -84,13 +84,13 @@ public void TestSetValues() DateTime dt = DateTime.Now.AddMilliseconds(123456789); cell.SetCellValue(dt); - Assert.IsTrue((dt.Ticks - cell.DateCellValue.Ticks) >= -20000); + Assert.IsTrue((dt.Ticks - ((DateTime)cell.DateCellValue).Ticks) >= -20000); Assert.AreEqual(CellType.Numeric, cell.CellType); AssertProhibitedValueAccess(cell, CellType.Boolean, CellType.String, CellType.Formula, CellType.Error); cell.SetCellValue(dt); - Assert.IsTrue((dt.Ticks - cell.DateCellValue.Ticks) >= -20000); + Assert.IsTrue((dt.Ticks - ((DateTime)cell.DateCellValue).Ticks) >= -20000); Assert.AreEqual(CellType.Numeric, cell.CellType); AssertProhibitedValueAccess(cell, CellType.Boolean, CellType.String, CellType.Formula, CellType.Error); diff --git a/testcases/ooxml/XSSF/UserModel/TestXSSFWorkbook.cs b/testcases/ooxml/XSSF/UserModel/TestXSSFWorkbook.cs index 0ae3c559f..69c4d59f7 100644 --- a/testcases/ooxml/XSSF/UserModel/TestXSSFWorkbook.cs +++ b/testcases/ooxml/XSSF/UserModel/TestXSSFWorkbook.cs @@ -1053,7 +1053,7 @@ public void TestBug56957CloseWorkbook() // read-only mode works! workbook = WorkbookFactory.Create(OPCPackage.Open(file, PackageAccess.READ)); - DateTime dateAct = workbook.GetSheetAt(0).GetRow(0).GetCell(0, MissingCellPolicy.CREATE_NULL_AS_BLANK).DateCellValue; + var dateAct = workbook.GetSheetAt(0).GetRow(0).GetCell(0, MissingCellPolicy.CREATE_NULL_AS_BLANK).DateCellValue; Assert.AreEqual(dateExp, dateAct); workbook.Close(); workbook = null;