diff --git a/samples/xlsx/TestIssue869/DateTimeMidnight.xlsx b/samples/xlsx/TestIssue869/DateTimeMidnight.xlsx
new file mode 100644
index 00000000..19d84975
Binary files /dev/null and b/samples/xlsx/TestIssue869/DateTimeMidnight.xlsx differ
diff --git a/samples/xlsx/TestIssue869/DateTimeNotMidnight.xlsx b/samples/xlsx/TestIssue869/DateTimeNotMidnight.xlsx
new file mode 100644
index 00000000..8aa35a60
Binary files /dev/null and b/samples/xlsx/TestIssue869/DateTimeNotMidnight.xlsx differ
diff --git a/src/MiniExcel.Core/Enums/DateOnlyConversionMode.cs b/src/MiniExcel.Core/Enums/DateOnlyConversionMode.cs
new file mode 100644
index 00000000..0955a87b
--- /dev/null
+++ b/src/MiniExcel.Core/Enums/DateOnlyConversionMode.cs
@@ -0,0 +1,20 @@
+namespace MiniExcelLib.Core.Enums;
+
+
+public enum DateOnlyConversionMode
+{
+ ///
+ /// No conversion is applied and DateOnly values are not transformed.
+ ///
+ None,
+
+ ///
+ /// Allows conversion from DateTime to DateOnly only if the time component is exactly midnight (00:00:00).
+ ///
+ RequireMidnight,
+
+ ///
+ /// Converts DateTime to DateOnly by ignoring the time part completely, assuming the time component is not critical.
+ ///
+ IgnoreTimePart
+}
\ No newline at end of file
diff --git a/src/MiniExcel.Core/MiniExcelConfiguration.cs b/src/MiniExcel.Core/MiniExcelConfiguration.cs
index e5ec3ea0..fee2ac1e 100644
--- a/src/MiniExcel.Core/MiniExcelConfiguration.cs
+++ b/src/MiniExcel.Core/MiniExcelConfiguration.cs
@@ -1,4 +1,5 @@
using MiniExcelLib.Core.Attributes;
+using MiniExcelLib.Core.Enums;
namespace MiniExcelLib.Core;
@@ -15,4 +16,9 @@ public abstract class MiniExcelBaseConfiguration : IMiniExcelConfiguration
/// When exporting using DataReader, the data not in DynamicColumn will be filtered.
///
public bool DynamicColumnFirst { get; set; } = false;
+
+ ///
+ /// Specifies when and how DateTime values are converted to DateOnly values.
+ ///
+ public DateOnlyConversionMode DateOnlyConversionMode { get; set; }
}
\ No newline at end of file
diff --git a/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs b/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs
index 055da0c2..7e46339d 100644
--- a/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs
+++ b/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs
@@ -1,4 +1,5 @@
using System.ComponentModel;
+using MiniExcelLib.Core.Enums;
using MiniExcelLib.Core.Exceptions;
namespace MiniExcelLib.Core.Reflection;
@@ -150,6 +151,14 @@ public static partial class MiniExcelMapper
return newValue;
}
+ if (itemValue is DateTime dateTimeValue && config.DateOnlyConversionMode is not DateOnlyConversionMode.None)
+ {
+ if (config.DateOnlyConversionMode == DateOnlyConversionMode.RequireMidnight && dateTimeValue.TimeOfDay != TimeSpan.Zero)
+ throw new InvalidCastException($"Could not convert cell of type DateTime to DateOnly, because DateTime was not at midnight, but at {dateTimeValue:HH:mm:ss}.");
+
+ return DateOnly.FromDateTime(dateTimeValue);
+ }
+
var vs = itemValue?.ToString();
if (pInfo.ExcelFormat is not null)
{
diff --git a/tests/MiniExcel.Core.Tests/MiniExcelIssueTests.cs b/tests/MiniExcel.Core.Tests/MiniExcelIssueTests.cs
index c9a4e98e..6bab7c52 100644
--- a/tests/MiniExcel.Core.Tests/MiniExcelIssueTests.cs
+++ b/tests/MiniExcel.Core.Tests/MiniExcelIssueTests.cs
@@ -1,5 +1,6 @@
using System.ComponentModel;
using System.Text.RegularExpressions;
+using MiniExcelLib.Core.Enums;
using MiniExcelLib.Core.Exceptions;
using MiniExcelLib.Core.OpenXml.Picture;
using MiniExcelLib.Core.OpenXml.Utils;
@@ -16,9 +17,7 @@ public class MiniExcelIssueTests(ITestOutputHelper output)
private readonly OpenXmlExporter _excelExporter = MiniExcel.Exporters.GetOpenXmlExporter();
private readonly OpenXmlTemplater _excelTemplater = MiniExcel.Templaters.GetOpenXmlTemplater();
- // private readonly OpenXmlImporter _csvImporter = MiniExcel.Importer.GetCsvImporter();
- // private readonly OpenXmlExporter _csvExporter = MiniExcel.Exporter.GetCsvExporter();
-
+
///
/// https://github.com/mini-software/MiniExcel/issues/549
///
@@ -3653,4 +3652,41 @@ public void TestIssue809()
Assert.Equal(null, rows[0].A);
Assert.Equal(2, rows[2].B);
}
+
+
+ private class Issue869
+ {
+ public string? Name { get; set; }
+ public DateOnly? Date { get; set; }
+ }
+
+ [Theory]
+ [InlineData("DateTimeMidnight", DateOnlyConversionMode.None, true)]
+ [InlineData("DateTimeNotMidnight", DateOnlyConversionMode.None, true)]
+ [InlineData("DateTimeMidnight", DateOnlyConversionMode.RequireMidnight, false)]
+ [InlineData("DateTimeNotMidnight", DateOnlyConversionMode.RequireMidnight, true)]
+ [InlineData("DateTimeMidnight", DateOnlyConversionMode.IgnoreTimePart, false)]
+ [InlineData("DateTimeNotMidnight", DateOnlyConversionMode.IgnoreTimePart, false)]
+ public void TestIssue869(string fileName, DateOnlyConversionMode mode, bool throwsException)
+ {
+ var path = PathHelper.GetFile($"xlsx/TestIssue869/{fileName}.xlsx");
+ var config = new OpenXmlConfiguration { DateOnlyConversionMode = mode };
+
+ var testFn = () => _excelImporter.Query(path, configuration: config).ToList();
+ if (throwsException)
+ {
+ Assert.Throws(testFn);
+ }
+ else
+ {
+ try
+ {
+ _ = testFn();
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail($"No exception should be thrown, but one was still thrown: {ex}.");
+ }
+ }
+ }
}
\ No newline at end of file